# -*- coding: UTF-8 -*-
#
#       core.py
#       
#       Copyright 2009-2011 Giuseppe Penone <giuspen@gmail.com>
#       
#       This program is free software; you can redistribute it and/or modify
#       it under the terms of the GNU General Public License as published by
#       the Free Software Foundation; either version 2 of the License, or
#       (at your option) any later version.
#       
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#       
#       You should have received a copy of the GNU General Public License
#       along with this program; if not, write to the Free Software
#       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#       MA 02110-1301, USA.

import gtk, pango, gtksourceview2, gobject
import sys, os, re, subprocess, webbrowser, base64, cgi, urllib2, shutil
import cons, support, config, machines, clipboard, imports, exports, printing, tablez, lists, findreplace, codeboxes


class GladeWidgetsWrapper:
   """Handles the retrieval of glade widgets"""
   
   def __init__(self, glade_file_path, gui_instance):
      try:
         self.glade_widgets = gtk.Builder()
         self.glade_widgets.set_translation_domain(cons.APP_NAME)
         self.glade_widgets.add_from_file(glade_file_path)
         self.glade_widgets.connect_signals(gui_instance)
      except: print "Failed to load the glade file"
      
   def __getitem__(self, key):
      """Gives us the ability to do: wrapper['widget_name'].action()"""
      return self.glade_widgets.get_object(key)
      
   def __getattr__(self, attr):
      """Gives us the ability to do: wrapper.widget_name.action()"""
      new_widget = self.glade_widgets.get_object(attr)
      if new_widget is None: raise AttributeError, 'Widget %r not found' % attr
      setattr(self, attr, new_widget)
      return new_widget


class CherryTree:
   """Application's GUI"""
   
   def __init__(self, lang_str, open_with_file, boss):
      """GUI Startup"""
      self.boss = boss
      self.user_active = True
      # instantiate external handlers
      self.clipboard_handler = clipboard.ClipboardHandler(self)
      self.lists_handler = lists.ListsHandler(self)
      self.tables_handler = tablez.TablesHandler(self)
      self.codeboxes_handler = codeboxes.CodeBoxesHandler(self)
      self.state_machine = machines.StateMachine(self)
      self.xml_handler = machines.XMLHandler(self)
      self.html_handler = exports.Export2Html(self)
      self.find_handler = findreplace.FindReplace(self)
      self.print_handler = printing.PrintHandler()
      # icon factory
      factory = gtk.IconFactory()
      for stock_name in cons.STOCKS_N_FILES:
         pixbuf = gtk.gdk.pixbuf_new_from_file(cons.GLADE_PATH + cons.STOCKS_N_FILES[stock_name])
         iconset = gtk.IconSet(pixbuf)
         factory.add(stock_name, iconset)
      factory.add_default()
      try: gtk.settings_get_default().set_property("gtk-button-images", True)
      except: pass # older gtk do not have the property "gtk-button-images"
      # glade
      self.glade = GladeWidgetsWrapper(cons.GLADE_PATH + 'cherrytree.glade', self) # glade widgets access
      self.window = self.glade.window
      vbox_main = gtk.VBox()
      self.window.add(vbox_main)
      self.country_lang = lang_str
      config.config_file_load(self)
      # ui manager
      actions = gtk.ActionGroup("Actions")
      actions.add_actions(cons.get_entries(self))
      self.ui = gtk.UIManager()
      self.ui.insert_action_group(actions, 0)
      self.window.add_accel_group(self.ui.get_accel_group())
      self.ui.add_ui_from_string(cons.UI_INFO)
      # menubar add
      vbox_main.pack_start(self.ui.get_widget("/MenuBar"), False, False)
      # toolbar add
      vbox_main.pack_start(self.ui.get_widget("/ToolBar"), False, False)
      # hpaned add
      self.hpaned = gtk.HPaned()
      self.scrolledwindow_tree = gtk.ScrolledWindow()
      self.scrolledwindow_tree.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
      self.scrolledwindow_text = gtk.ScrolledWindow()
      self.scrolledwindow_text.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
      self.vbox_text = gtk.VBox()
      self.header_node_name_label = gtk.Label()
      self.vbox_text.pack_start(self.header_node_name_label, False, False)
      self.vbox_text.pack_start(self.scrolledwindow_text)
      if self.tree_right_side:
         self.hpaned.add1(self.vbox_text)
         self.hpaned.add2(self.scrolledwindow_tree)
      else:
         self.hpaned.add1(self.scrolledwindow_tree)
         self.hpaned.add2(self.vbox_text)
      vbox_main.pack_start(self.hpaned)
      # statusbar add
      self.statusbar = gtk.Statusbar()
      self.statusbar_context_id = self.statusbar.get_context_id('')
      vbox_main.pack_start(self.statusbar, False, False)
      # ROW: 0-icon_stock_id, 1-name, 2-buffer, 3-unique_id, 4-syntax_highlighting, 5-level, 6-tags, 7-readonly
      self.treestore = gtk.TreeStore(str, str, gobject.TYPE_PYOBJECT, long, str, int, str, gobject.TYPE_BOOLEAN)
      self.treeview = gtk.TreeView(self.treestore)
      self.treeview.set_headers_visible(False)
      self.treeview.drag_source_set(gtk.gdk.BUTTON1_MASK,
                                    [('CT_DND', gtk.TARGET_SAME_WIDGET, 0)],
                                    gtk.gdk.ACTION_MOVE)
      self.treeview.drag_dest_set(gtk.DEST_DEFAULT_ALL,
                                  [('CT_DND', gtk.TARGET_SAME_WIDGET, 0)],
                                  gtk.gdk.ACTION_MOVE)
      self.renderer_pixbuf = gtk.CellRendererPixbuf()
      self.renderer_text = gtk.CellRendererText()
      self.renderer_text.set_property('wrap-mode', pango.WRAP_WORD_CHAR)
      self.renderer_text.connect('edited', self.tree_cell_edited)
      self.column = gtk.TreeViewColumn()
      self.column.pack_start(self.renderer_pixbuf, False)
      self.column.pack_start(self.renderer_text, True)
      self.column.set_attributes(self.renderer_pixbuf, stock_id=0)
      self.column.set_attributes(self.renderer_text, text=1)
      self.treeview.append_column(self.column)
      self.treeviewselection = self.treeview.get_selection()
      self.treeview.connect('cursor-changed', self.on_node_changed)
      self.treeview.connect('button-press-event', self.on_mouse_button_clicked_tree)
      self.treeview.connect('key_press_event', self.on_key_press_cherrytree)
      self.treeview.connect('drag-motion', self.on_drag_motion_cherrytree)
      self.treeview.connect('drag-data-received', self.on_drag_data_recv_cherrytree)
      self.treeview.connect('drag-data-get', self.on_drag_data_get_cherrytree)
      self.treeview.connect("motion-notify-event", self.on_treeview_motion_notify_event)
      self.scrolledwindow_tree.add(self.treeview)
      self.orphan_accel_group = gtk.AccelGroup()
      self.menu_tree_create()
      self.window.connect('window-state-event', self.on_window_state_event)
      self.window.connect("size-allocate", self.on_window_n_tree_size_allocate_event)
      self.window.connect('key_press_event', self.on_key_press_window)
      self.window.connect("destroy", self.boss.on_window_destroy_event)
      self.scrolledwindow_tree.connect("size-allocate", self.on_window_n_tree_size_allocate_event)
      self.glade.inputdialog.connect('key_press_event', self.on_key_press_input_dialog)
      self.glade.anchorhandledialog.connect('key_press_event', self.on_key_press_anchorhandledialog)
      self.glade.choosenodedialog.connect('key_press_event', self.on_key_press_choosenodedialog)
      self.glade.tablehandledialog.connect('key_press_event', self.tables_handler.on_key_press_tablehandledialog)
      self.glade.codeboxhandledialog.connect('key_press_event', self.codeboxes_handler.on_key_press_codeboxhandledialog)
      self.sourceview = gtksourceview2.View()
      self.sourceview.set_sensitive(False)
      self.sourceview.connect('populate-popup', self.on_sourceview_populate_popup)
      self.sourceview.connect("motion-notify-event", self.on_sourceview_motion_notify_event)
      self.sourceview.connect("event-after", self.on_sourceview_event_after)
      self.sourceview.connect("visibility-notify-event", self.on_sourceview_visibility_notify_event)
      self.sourceview.connect("copy-clipboard", self.clipboard_handler.copy)
      self.sourceview.connect("cut-clipboard", self.clipboard_handler.cut)
      self.sourceview.connect("paste-clipboard", self.clipboard_handler.paste)
      self.sourceview.set_left_margin(7)
      self.sourceview.set_right_margin(7)
      self.hovering_over_link = False
      self.tag_table = gtk.TextTagTable()
      self.scrolledwindow_text.add(self.sourceview)
      self.go_bk_fw_click = False
      self.highlighted_obj = None
      self.bookmarks = []
      self.bookmarks_menu_items = []
      self.nodes_names_dict = {}
      self.password = None
      self.curr_tree_iter = None
      self.curr_window_n_tree_width = None
      self.curr_buffer = None
      self.curr_colors = {'f':None, 'b':None}
      self.nodes_cursor_pos = {}
      self.latest_tag = ["", ""] # [latest tag property, latest tag value]
      self.file_update = False
      self.autosave_timer_id = None
      self.node_id_counter = long(0)
      self.glade.aboutdialog.set_version(cons.VERSION)
      support.set_menu_items_recent_documents(self)
      self.window.show_all() # this before the config_file_apply that could hide something
      self.window.present()
      config.config_file_apply(self)
      self.combobox_country_lang_init()
      self.combobox_prog_lang_init()
      if self.systray:
         self.status_icon_enable()
         if self.start_on_systray: self.window.hide()
      else: self.ui.get_widget("/MenuBar/FileMenu/ExitApp").set_property('visible', False)
      self.file_startup_load(open_with_file)
      if self.check_version: self.check_for_newer_version()
      else: self.statusbar.push(self.statusbar_context_id, _("Version %s") % cons.VERSION)
      
   def check_for_newer_version(self, *args):
      """Check for a Newer Version"""
      self.statusbar.push(self.statusbar_context_id, _("Checking for Newer Version..."))
      while gtk.events_pending(): gtk.main_iteration()
      try:
         fd = urllib2.urlopen(cons.NEWER_VERSION_URL, timeout=3)
         latest_version = fd.read().replace("\n", "")
         if latest_version != cons.VERSION:
            support.dialog_info(_("A Newer Version Is Available!") + " (%s)" % latest_version, self.window)
      except: pass
      self.statusbar.push(self.statusbar_context_id, _("Version %s") % cons.VERSION)
      
   def get_node_icon(self, node_level, node_code):
      """Returns the Stock Id given the Node Level"""
      if self.nodes_icons == "c":
         if node_code == cons.CUSTOM_COLORS_ID:
            if node_level in cons.NODES_ICONS: return cons.NODES_ICONS[node_level]
            else: return cons.NODES_ICONS[6]
         else:
            if node_code in cons.CODE_ICONS: return cons.CODE_ICONS[node_code]
            else: return "Gray Cherry"
      elif self.nodes_icons == "b": return "Node Bullet"
      else: return "Node NoIcon"
      
   def text_selection_change_case(self, change_type):
      """Change the Case of the Selected Text/the Underlying Word"""
      if not self.curr_buffer.get_has_selection() and not self.apply_tag_try_automatic_bounds():
         support.dialog_warning(_("No Text is Selected"), self.window)
         return
      iter_start, iter_end = self.curr_buffer.get_selection_bounds()
      if self.syntax_highlighting != cons.CUSTOM_COLORS_ID:
         text_to_change_case = self.curr_buffer.get_slice(iter_start, iter_end)
         if change_type == "l": text_to_change_case = text_to_change_case.lower()
         elif change_type == "u": text_to_change_case = text_to_change_case.upper()
         elif change_type == "t": text_to_change_case = text_to_change_case.swapcase()
      else:
         rich_text = self.clipboard_handler.rich_text_get_from_text_buffer_selection(self.curr_buffer,
                                                                                     iter_start,
                                                                                     iter_end,
                                                                                     change_case=change_type)
      start_offset = iter_start.get_offset()
      end_offset = iter_end.get_offset()
      self.curr_buffer.delete(iter_start, iter_end)
      iter_insert = self.curr_buffer.get_iter_at_offset(start_offset)
      if self.syntax_highlighting != cons.CUSTOM_COLORS_ID:
         self.curr_buffer.insert(iter_insert, text_to_change_case)
      else:
         self.curr_buffer.move_mark(self.curr_buffer.get_insert(), iter_insert)
         self.clipboard_handler.from_xml_string_to_buffer(rich_text)
      self.curr_buffer.select_range(self.curr_buffer.get_iter_at_offset(start_offset),
                                    self.curr_buffer.get_iter_at_offset(end_offset))
      
   def text_selection_toggle_case(self, *args):
      """Toggles the Case of the Selected Text/the Underlying Word"""
      self.text_selection_change_case("t")
      
   def text_selection_upper_case(self, *args):
      """Uppers the Case of the Selected Text/the Underlying Word"""
      self.text_selection_change_case("u")
   
   def text_selection_lower_case(self, *args):
      """Lowers the Case of the Selected Text/the Underlying Word"""
      self.text_selection_change_case("l")
      
   def text_row_selection_duplicate(self, *args):
      """Duplicates the Whole Row or a Selection"""
      if self.curr_buffer.get_has_selection():
         iter_start, iter_end = self.curr_buffer.get_selection_bounds() # there's a selection
         sel_start_offset = iter_start.get_offset()
         sel_end_offset = iter_end.get_offset()
         if self.syntax_highlighting != cons.CUSTOM_COLORS_ID:
            text_to_duplicate = self.curr_buffer.get_slice(iter_start, iter_end)
            if cons.CHAR_NEWLINE in text_to_duplicate:
               text_to_duplicate = cons.CHAR_NEWLINE + text_to_duplicate
            self.curr_buffer.insert(iter_end, text_to_duplicate)
         else:
            rich_text = self.clipboard_handler.rich_text_get_from_text_buffer_selection(self.curr_buffer,
                                                                                        iter_start,
                                                                                        iter_end)
            if cons.CHAR_NEWLINE in rich_text:
               self.curr_buffer.insert(iter_end, cons.CHAR_NEWLINE)
               iter_end = self.curr_buffer.get_iter_at_offset(sel_end_offset+1)
               self.curr_buffer.move_mark(self.curr_buffer.get_insert(), iter_end)
            self.clipboard_handler.from_xml_string_to_buffer(rich_text)
         self.curr_buffer.select_range(self.curr_buffer.get_iter_at_offset(sel_start_offset),
                                       self.curr_buffer.get_iter_at_offset(sel_end_offset))
      else:
         iter_start, iter_end = self.lists_handler.get_paragraph_iters()
         if iter_start == None:
            iter_start = self.curr_buffer.get_iter_at_mark(self.curr_buffer.get_insert())
            self.curr_buffer.insert(iter_start, cons.CHAR_NEWLINE)
         else:
            if self.syntax_highlighting != cons.CUSTOM_COLORS_ID:
               text_to_duplicate = self.curr_buffer.get_slice(iter_start, iter_end)
               self.curr_buffer.insert(iter_end, cons.CHAR_NEWLINE + text_to_duplicate)
            else:
               rich_text = self.clipboard_handler.rich_text_get_from_text_buffer_selection(self.curr_buffer,
                                                                                           iter_start,
                                                                                           iter_end)
               sel_end_offset = iter_end.get_offset()
               self.curr_buffer.insert(iter_end, cons.CHAR_NEWLINE)
               iter_end = self.curr_buffer.get_iter_at_offset(sel_end_offset+1)
               self.curr_buffer.move_mark(self.curr_buffer.get_insert(), iter_end)
               self.clipboard_handler.from_xml_string_to_buffer(rich_text)
      self.state_machine.update_state(self.treestore[self.curr_tree_iter][3])
      
   def text_row_delete(self, *args):
      """Deletes the Whole Row"""
      iter_start, iter_end = self.lists_handler.get_paragraph_iters()
      if iter_start == None:
         iter_start = self.curr_buffer.get_iter_at_mark(self.curr_buffer.get_insert())
         iter_end = iter_start.copy()
      if not iter_end.forward_char() and not iter_start.backward_char(): return
      self.curr_buffer.delete(iter_start, iter_end)
      self.state_machine.update_state(self.treestore[self.curr_tree_iter][3])
      
   def text_row_cut(self, *args):
      """Cut a Whole Row"""
      iter_start, iter_end = self.lists_handler.get_paragraph_iters()
      if iter_start == None:
         iter_start = self.curr_buffer.get_iter_at_mark(self.curr_buffer.get_insert())
         iter_end = iter_start.copy()
      if not iter_end.forward_char() and not iter_start.backward_char(): return
      self.curr_buffer.select_range(iter_start, iter_end)
      self.sourceview.emit("cut-clipboard")
      
   def text_row_copy(self, *args):
      """Copy a Whole Row"""
      iter_start, iter_end = self.lists_handler.get_paragraph_iters()
      if iter_start == None:
         iter_start = self.curr_buffer.get_iter_at_mark(self.curr_buffer.get_insert())
         iter_end = iter_start.copy()
      if not iter_end.forward_char() and not iter_start.backward_char(): return
      self.curr_buffer.select_range(iter_start, iter_end)
      self.sourceview.emit("copy-clipboard")
      
   def on_key_press_window(self, widget, event):
      """Catches Window key presses"""
      if not self.curr_tree_iter: return
      keyname = gtk.gdk.keyval_name(event.keyval)
      if event.state & gtk.gdk.MOD1_MASK:
         if keyname == "Left": self.go_back()
         elif keyname == "Right": self.go_forward()
      
   def on_key_press_cherrytree(self, widget, event):
      """Catches Tree key presses"""
      if not self.curr_tree_iter: return
      keyname = gtk.gdk.keyval_name(event.keyval)
      if event.state & gtk.gdk.SHIFT_MASK:
         if keyname == "Up": self.node_up()
         elif keyname == "Down": self.node_down()
         elif keyname == "Left": self.node_left()
         elif keyname == "Right": self.node_change_father()
      elif event.state & gtk.gdk.MOD1_MASK:
         pass
      elif event.state & gtk.gdk.CONTROL_MASK:
         pass
      else:
         if keyname == "Up":
            prev_iter = self.get_tree_iter_prev_sibling(self.treestore, self.curr_tree_iter)
            if prev_iter: self.treeview_safe_set_cursor(prev_iter)
         elif keyname == "Down":
            next_iter = self.treestore.iter_next(self.curr_tree_iter)
            if next_iter: self.treeview_safe_set_cursor(next_iter)
         elif keyname == "Left":
            father_iter = self.treestore.iter_parent(self.curr_tree_iter)
            if father_iter: self.treeview_safe_set_cursor(father_iter)
         elif keyname == "Right":
            child_iter = self.treestore.iter_children(self.curr_tree_iter)
            if child_iter: self.treeview_safe_set_cursor(child_iter)
         elif keyname == "Return": self.node_edit()
         elif keyname == "Delete": self.node_delete()
         elif keyname == "Menu":
            self.menu_tree.popup(None, None, None, 0, event.time)
      widget.stop_emission("key_press_event")
   
   def fullscreen_toggle(self, *args):
      """Toggle Fullscreen State"""
      if (self.window.window.get_state() & gtk.gdk.WINDOW_STATE_FULLSCREEN):
         self.window.window.unfullscreen()
      else:
         self.window.window.fullscreen()
   
   def on_drag_motion_cherrytree(self, widget, drag_context, x, y, timestamp):
      """Cherry Tree drag motion"""
      drop_info = self.treeview.get_dest_row_at_pos(x, y)
      if drop_info:
         drop_path, drop_pos = drop_info
         widget.set_drag_dest_row(drop_path, drop_pos)
      return True
   
   def on_drag_data_recv_cherrytree(self, widget, drag_context, x, y, selection_data, info, timestamp):
      """Cherry Tree drag data received"""
      drop_info = self.treeview.get_dest_row_at_pos(x, y)
      if drop_info:
         drop_path, drop_pos = drop_info
         if not drop_pos: drop_pos = gtk.TREE_VIEW_DROP_BEFORE
         drop_iter = self.treestore.get_iter(drop_path)
         # check for bad drop
         if not self.drag_iter: return False
         drag_node_id = self.treestore[self.drag_iter][3]
         if self.treestore[drop_iter][3] == drag_node_id:
            print "drag node and drop node are the same"
            return False
         move_towards_top_iter = self.treestore.iter_parent(drop_iter)
         while move_towards_top_iter:
            if self.treestore[move_towards_top_iter][3] == drag_node_id:
               support.dialog_error(_("The new father can't be one of his sons!"), self.window)
               return False
            move_towards_top_iter = self.treestore.iter_parent(move_towards_top_iter)
         if drop_pos == gtk.TREE_VIEW_DROP_BEFORE:
            prev_iter = self.get_tree_iter_prev_sibling(self.treestore, drop_iter)
            self.node_move_after(self.drag_iter, self.treestore.iter_parent(drop_iter), prev_iter, True)
         elif drop_pos == gtk.TREE_VIEW_DROP_AFTER:
            self.node_move_after(self.drag_iter, self.treestore.iter_parent(drop_iter), drop_iter)
         else: # drop in
            self.node_move_after(self.drag_iter, drop_iter)
         if self.nodes_icons == "c": self.treeview_refresh(change_icon=True)
      return True
      
   def on_drag_data_get_cherrytree(self, widget, drag_context, selection_data, info, timestamp):
      """Cherry Tree drag data received"""
      tree_model, tree_iter = self.treeviewselection.get_selected()
      self.drag_iter = tree_iter
      selection_data.set("UTF8_STRING", 8, "fake") # without this, the drag_data_recv will not be called
      return True
   
   def on_key_press_choosenodedialog(self, widget, event):
      """Catches ChooseNode Dialog key presses"""
      keyname = gtk.gdk.keyval_name(event.keyval)
      if keyname == "Return": self.glade.choosenodedialog_button_ok.clicked()
   
   def on_key_press_anchorhandledialog(self, widget, event):
      """Catches AnchorHandle Dialog key presses"""
      keyname = gtk.gdk.keyval_name(event.keyval)
      if keyname == "Return": self.glade.anchorhandledialog_button_ok.clicked()
      
   def on_key_press_input_dialog(self, widget, event):
      """Catches Input Dialog key presses"""
      keyname = gtk.gdk.keyval_name(event.keyval)
      if keyname == "Return": self.glade.input_dialog_ok_button.clicked()
      
   def nodes_add_from_cherrytree_file(self, action):
      """Appends Nodes at the Bottom of the Current Ones, Importing from a CherryTree File"""
      filepath = support.dialog_file_select(filter_pattern="*.ct*",
                                            filter_name=_("CherryTree Document"),
                                            curr_folder=self.file_dir,
                                            parent=self.window)
      if filepath == None: return
      try: cherrytree_string = self.file_get_cherrytree_xml(filepath, False)
      except:
         support.dialog_error("Error opening the file %s" % filepath, self.window)
         return
      if cherrytree_string: self.nodes_add_from_string(cherrytree_string)
      
   def nodes_add_from_notecase_file(self, action):
      """Add Nodes Parsing a NoteCase File"""
      filepath = support.dialog_file_select(filter_pattern="*.ncd",
                                            filter_name=_("NoteCase Document"),
                                            curr_folder=self.file_dir,
                                            parent=self.window)
      if filepath == None: return
      try:
         file_descriptor = open(filepath, 'r')
         notecase_string = file_descriptor.read()
         file_descriptor.close()
      except:
         support.dialog_error("Error opening the file %s" % filepath, self.window)
         return
      notecase = imports.NotecaseHandler()
      cherrytree_string = notecase.get_cherrytree_xml(notecase_string)
      self.nodes_add_from_string(cherrytree_string)
      
   def nodes_add_from_tuxcards_file(self, action):
      """Add Nodes Parsing a TuxCards File"""
      filepath = support.dialog_file_select(curr_folder=self.file_dir,
                                            parent=self.window)
      if filepath == None: return
      try:
         file_descriptor = open(filepath, 'r')
         tuxcards_string = file_descriptor.read()
         file_descriptor.close()
      except:
         support.dialog_error("Error opening the file %s" % filepath, self.window)
         return
      tuxcards = imports.TuxCardsHandler()
      cherrytree_string = tuxcards.get_cherrytree_xml(tuxcards_string)
      self.nodes_add_from_string(cherrytree_string)
      
   def nodes_add_from_keepnote_folder(self, action):
      """Add Nodes Parsing a KeepNote Folder"""
      folderpath = support.dialog_folder_select(curr_folder=self.file_dir, parent=self.window)
      if folderpath == None: return
      keepnote = imports.KeepnoteHandler(folderpath)
      cherrytree_string = keepnote.get_cherrytree_xml()
      self.nodes_add_from_string(cherrytree_string)
      
   def nodes_add_from_tomboy_folder(self, action):
      """Add Nodes Parsing a Tomboy Folder"""
      start_folder = os.path.join(os.path.expanduser('~'), ".local/share/tomboy")
      folderpath = support.dialog_folder_select(curr_folder=start_folder, parent=self.window)
      if folderpath == None: return
      tomboy = imports.TomboyHandler(folderpath)
      cherrytree_string = tomboy.get_cherrytree_xml()
      self.nodes_add_from_string(cherrytree_string)
      tomboy.set_links_to_nodes(self)
      
   def nodes_add_from_basket_folder(self, action):
      """Add Nodes Parsing a Basket Folder"""
      start_folder = os.path.join(os.path.expanduser('~'), ".kde/share/apps/basket/baskets")
      folderpath = support.dialog_folder_select(curr_folder=start_folder, parent=self.window)
      if folderpath == None: return
      basket = imports.BasketHandler(folderpath)
      if basket.check_basket_structure():
         cherrytree_string = basket.get_cherrytree_xml()
         self.nodes_add_from_string(cherrytree_string)
      
   def nodes_add_from_treepad_file(self, action):
      """Add Nodes Parsing a Treepad File"""
      filepath = support.dialog_file_select(filter_pattern="*.hjt",
                                            filter_name=_("Treepad Document"),
                                            curr_folder=self.file_dir,
                                            parent=self.window)
      if filepath == None: return
      try:
         file_descriptor = open(filepath, 'r')
         treepad = imports.TreepadHandler()
         cherrytree_string = treepad.get_cherrytree_xml(file_descriptor)
         file_descriptor.close()
      except:
         support.dialog_error("Error opening the file %s" % filepath, self.window)
         return
      self.nodes_add_from_string(cherrytree_string)
      
   def nodes_add_from_knowit_file(self, action):
      """Add Nodes Parsing a Knowit File"""
      filepath = support.dialog_file_select(filter_pattern="*.kno",
                                            filter_name=_("Knowit Document"),
                                            curr_folder=self.file_dir,
                                            parent=self.window)
      if filepath == None: return
      try:
         file_descriptor = open(filepath, 'r')
         knowit = imports.KnowitHandler()
         cherrytree_string = knowit.get_cherrytree_xml(file_descriptor)
         file_descriptor.close()
      except:
         support.dialog_error("Error opening the file %s" % filepath, self.window)
         return
      self.nodes_add_from_string(cherrytree_string)
      
   def nodes_add_from_leo_file(self, action):
      """Add Nodes Parsing a Leo File"""
      filepath = support.dialog_file_select(filter_pattern="*.leo",
                                            filter_name=_("Leo Document"),
                                            curr_folder=self.file_dir,
                                            parent=self.window)
      if filepath == None: return
      try:
         file_descriptor = open(filepath, 'r')
         leo_string = file_descriptor.read()
         file_descriptor.close()
      except:
         support.dialog_error("Error opening the file %s" % filepath, self.window)
         return
      leo = imports.LeoHandler()
      cherrytree_string = leo.get_cherrytree_xml(leo_string)
      self.nodes_add_from_string(cherrytree_string)
      
   def nodes_add_from_string(self, cherrytree_string):
      """Adds Nodes to the Tree Parsing a CherryTree XML String"""
      cherrytree_string = re.sub(cons.BAD_CHARS, "", cherrytree_string)
      self.user_active = False
      file_loaded = False
      former_node = self.curr_tree_iter # we'll restore after the import
      tree_father = None # init the value of the imported nodes father
      if self.curr_tree_iter:
         self.nodes_cursor_pos[self.treestore[self.curr_tree_iter][3]] = self.curr_buffer.get_property('cursor-position')
         if self.curr_buffer.get_modified() == True:
            self.file_update = True
            self.curr_buffer.set_modified(False)
            self.state_machine.update_state(self.treestore[self.curr_tree_iter][3])
         append_location_dialog = gtk.Dialog(title=_("Who is the Father?"),
                                             parent=self.window,
                                             flags=gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
                                             buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
                                                      gtk.STOCK_OK, gtk.RESPONSE_ACCEPT) )
         append_location_dialog.set_transient_for(self.window)
         append_location_dialog.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
         radiobutton_root = gtk.RadioButton(label=_("The Tree Root"))
         radiobutton_curr_node = gtk.RadioButton(label=_("The Selected Node"))
         radiobutton_curr_node.set_group(radiobutton_root)
         content_area = append_location_dialog.get_content_area()
         content_area.pack_start(radiobutton_root)
         content_area.pack_start(radiobutton_curr_node)
         content_area.show_all()
         response = append_location_dialog.run()
         if radiobutton_curr_node.get_active(): tree_father = self.curr_tree_iter
         append_location_dialog.destroy()
         if response != gtk.RESPONSE_ACCEPT:
            self.user_active = True
            return
      try:
         # the imported nodes unique_ids must be discarded!
         if self.xml_handler.dom_to_treestore(cherrytree_string, discard_ids=True,
                                              tree_father=tree_father, reset_nodes_names=False):
            if self.expand_tree: self.treeview.expand_all()
            file_loaded = True
      except: pass
      if file_loaded:
         self.update_window_save_needed()
         if not former_node: former_node = self.treestore.get_iter_first()
         if former_node:
            self.curr_tree_iter = former_node
            self.curr_buffer = self.treestore[self.curr_tree_iter][2]
            self.sourceview.set_buffer(None)
            self.sourceview.set_buffer(self.curr_buffer)
            self.syntax_highlighting = self.treestore[self.curr_tree_iter][4]
            self.curr_buffer.connect('modified-changed', self.on_modified_changed)
            if self.syntax_highlighting == cons.CUSTOM_COLORS_ID:
               self.curr_buffer.connect('insert-text', self.on_text_insertion)
               self.curr_buffer.connect('delete-range', self.on_text_removal)
               self.sourceview.modify_font(pango.FontDescription(self.text_font))
            else: self.sourceview.modify_font(pango.FontDescription(self.code_font))
            self.sourceview.set_sensitive(True)
            self.header_node_name_label.set_text("<big><b><i>"+cgi.escape(self.treestore[self.curr_tree_iter][1])+"</i></b></big>")
            self.header_node_name_label.set_use_markup(True)
            self.state_machine.node_selected_changed(self.treestore[self.curr_tree_iter][3])
            self.objects_buffer_refresh()
            # try to restore cursor position if in memory
            if self.treestore[former_node][3] in self.nodes_cursor_pos:
               self.curr_buffer.place_cursor(self.curr_buffer.get_iter_at_offset(self.nodes_cursor_pos[self.treestore[former_node][3]]))
               self.sourceview.scroll_to_mark(self.curr_buffer.get_insert(), 0.3)
      else: support.dialog_error('Error Parsing the CherryTree XML String', self.window)
      self.user_active = True
      
   def nodes_expand_all(self, action):
      """Expand all Tree Nodes"""
      self.treeview.expand_all()
      
   def nodes_collapse_all(self, action):
      """Collapse all Tree Nodes"""
      self.treeview.collapse_all()
      
   def on_sourceview_populate_popup(self, textview, menu):
      """Extend the Default Right-Click Menu"""
      if self.syntax_highlighting == cons.CUSTOM_COLORS_ID:
         for menuitem in menu.get_children():
            try:
               if menuitem.get_image().get_property("stock") == "gtk-paste":
                  menuitem.set_sensitive(True)
            except: pass
         self.menu_populate_popup(menu, cons.get_popup_menu_entries_text(self))
      else: self.menu_populate_popup(menu, cons.get_popup_menu_entries_code(self))
      
   def menu_populate_popup(self, menu, entries, accel_group=None):
      """Populate the given menu with the given entries"""
      if not accel_group: accel_group = self.ui.get_accel_group()
      curr_submenu = None
      for attributes in entries:
         if attributes[0] == "separator":
            menu_item = gtk.SeparatorMenuItem()
            if curr_submenu: curr_submenu.append(menu_item)
            else: menu.append(menu_item)
         elif attributes[0] == "submenu-start":
            curr_submenu = gtk.Menu()
            menu_item = gtk.ImageMenuItem(attributes[1])
            menu_item.set_image(gtk.image_new_from_stock(attributes[2], gtk.ICON_SIZE_MENU))
            menu_item.set_submenu(curr_submenu)
            menu.append(menu_item)
         elif attributes[0] == "submenu-end":
            curr_submenu = None
            continue
         else:
            menu_item = gtk.ImageMenuItem(attributes[1])
            menu_item.connect('activate', attributes[4])
            menu_item.set_image(gtk.image_new_from_stock(attributes[0], gtk.ICON_SIZE_MENU))
            menu_item.set_tooltip_text(attributes[3])
            if attributes[2]:
               key, mod = gtk.accelerator_parse(attributes[2])
               for element in ["Up", "Down", "Left", "Right", "Delete"]:
                  if element in attributes[2]:
                     accel_group = self.orphan_accel_group
                     break
               menu_item.add_accelerator("activate", accel_group, key, mod, gtk.ACCEL_VISIBLE)
            if curr_submenu: curr_submenu.append(menu_item)
            else: menu.append(menu_item)
         menu_item.show()
      
   def menu_tree_create(self):
      """Create the Tree Menus"""
      self.menu_tree = gtk.Menu()
      top_menu_tree = self.ui.get_widget("/MenuBar/TreeMenu").get_submenu()
      for menuitem in top_menu_tree:
         top_menu_tree.remove(menuitem)
      self.menu_populate_popup(top_menu_tree, cons.get_popup_menu_tree(self))
      self.menu_populate_popup(self.menu_tree, cons.get_popup_menu_tree(self))
      
   def on_window_state_event(self, window, event):
      """Catch Window's Events"""
      if event.changed_mask & gtk.gdk.WINDOW_STATE_MAXIMIZED:
         if event.new_window_state & gtk.gdk.WINDOW_STATE_MAXIMIZED:
            # the window was maximized
            self.win_is_maximized = True
         else:
            # the window was unmaximized
            self.win_is_maximized = False
      
   def dialog_preferences(self, *args):
      """Opens the Preferences Dialog"""
      self.glade.prefdialog.run()
      self.glade.prefdialog.hide()
      # timer activate/modify handling
      new_autosave_value = int(self.glade.spinbutton_autosave.get_value())
      if self.autosave[1] != new_autosave_value:
         self.autosave[1] = new_autosave_value
         if self.autosave_timer_id != None: self.autosave_timer_stop()
      if self.autosave[0] and self.autosave_timer_id == None: self.autosave_timer_start()
      
   def autosave_timer_start(self):
      """Start Autosave Timer"""
      self.autosave_timer_id = gobject.timeout_add(self.autosave[1]*1000*60, self.autosave_timer_iter)
      
   def autosave_timer_stop(self):
      """Stop Autosave Timer"""
      gobject.source_remove(self.autosave_timer_id)
      self.autosave_timer_id = None
      
   def autosave_timer_iter(self):
      """Iteration of the Autosave"""
      if self.file_update or (self.curr_tree_iter != None and self.curr_buffer.get_modified() == True):
         self.file_save()
      return True # this way we keep the timer alive
      
   def status_icon_enable(self):
      """Creates the Stats Icon"""
      self.status_icon = gtk.StatusIcon()
      self.status_icon.set_from_stock("CherryTree")
      self.status_icon.connect('button-press-event', self.on_mouse_button_clicked_systray)
      self.status_icon.set_tooltip(_("CherryTree Hierarchical Note Taking"))
   
   def on_mouse_button_clicked_systray(self, widget, event):
      """Catches mouse buttons clicks upon the system tray icon"""
      if event.button == 1:
         if self.window.get_property('visible'): self.window.hide()
         else:
            self.window.show()
            self.window.deiconify()
      elif event.button == 3: self.ui.get_widget("/SysTrayMenu").popup(None, None, None, event.button, event.time)
   
   def node_id_get(self):
      """Returns the node_ids, all Different Each Other"""
      self.node_id_counter += 1
      return self.node_id_counter
      
   def node_id_add(self, node_id):
      """Updates the Maximum node_id Value Considering the Received One"""
      if node_id > self.node_id_counter: self.node_id_counter = node_id
   
   def on_fontbutton_text_font_set(self, picker):
      """A New Font For the Text was Chosen"""
      self.text_font = picker.get_font_name()
      if self.treestore[self.curr_tree_iter][4] == cons.CUSTOM_COLORS_ID:
         self.sourceview.modify_font(pango.FontDescription(self.text_font))
      
   def on_fontbutton_code_font_set(self, picker):
      """A New Font For the Text was Chosen"""
      self.code_font = picker.get_font_name()
      if self.treestore[self.curr_tree_iter][4] != cons.CUSTOM_COLORS_ID:
         self.sourceview.modify_font(pango.FontDescription(self.code_font))
      
   def on_fontbutton_tree_font_set(self, picker):
      """A New Font For the Tree was Chosen"""
      self.tree_font = picker.get_font_name()
      self.set_treeview_font()
   
   def set_treeview_font(self):
      """Update the TreeView Font"""
      self.renderer_text.set_property('font-desc', pango.FontDescription(self.tree_font))
      self.treeview_refresh()
   
   def treeview_refresh(self, change_icon=False):
      """Refresh the Treeview"""
      if self.curr_buffer:
         if not self.expand_tree: config.get_tree_expanded_collapsed_string(self)
         self.treeview.set_model(None)
         if change_icon:
            tree_iter = self.treestore.get_iter_first()
            while tree_iter:
               self.change_icon_iter(tree_iter)
               tree_iter = self.treestore.iter_next(tree_iter)
         self.treeview.set_model(self.treestore)
         if self.expand_tree: self.treeview.expand_all()
         else: config.set_tree_expanded_collapsed_string(self)
         self.treeview.set_cursor(self.treestore.get_path(self.curr_tree_iter))
   
   def change_icon_iter(self, tree_iter):
      """Changing all icons type - iter"""
      father_iter = self.treestore.iter_parent(tree_iter)
      if father_iter: self.treestore[tree_iter][5] = self.treestore[father_iter][5] + 1
      else: self.treestore[tree_iter][5] = 0
      self.treestore[tree_iter][0] = self.get_node_icon(self.treestore[tree_iter][5], self.treestore[tree_iter][4])
      child_tree_iter = self.treestore.iter_children(tree_iter)
      while child_tree_iter:
         self.change_icon_iter(child_tree_iter)
         child_tree_iter = self.treestore.iter_next(child_tree_iter)
   
   def file_startup_load(self, open_with_file):
      """Try to load a file if there are the conditions"""
      if open_with_file:
         self.file_name = os.path.basename(open_with_file)
         self.file_dir = os.path.dirname(open_with_file)
      elif self.boss.running_windows:
         self.file_name = ""
         return
      if self.file_dir and self.file_name and os.path.isfile(os.path.join(self.file_dir, self.file_name)):
         self.file_load(os.path.join(self.file_dir, self.file_name))
         if self.expand_tree: self.treeview.expand_all()
         else: config.set_tree_expanded_collapsed_string(self) # restore expanded/collapsed nodes
         # we put the cursor on the first node as default
         first_node_iter = self.treestore.get_iter_first()
         if first_node_iter != None:
            self.treeview.set_cursor(self.treestore.get_path(first_node_iter))
            self.sourceview.grab_focus()
            # but then we try restore the latest situation
            if self.node_path != None:
               if self.treestore.get_path(first_node_iter) != self.node_path:
                  self.state_machine.forget_last_visited()
               self.treeview.set_cursor(self.node_path)
               self.sourceview.grab_focus()
               self.curr_buffer.place_cursor(self.curr_buffer.get_iter_at_offset(self.cursor_position))
               self.sourceview.scroll_to_mark(self.curr_buffer.get_insert(), 0.3)
      else: self.file_name = ""
      self.file_update = False
      
   def on_modified_changed(self, sourcebuffer):
      """When the modification flag is changed"""
      if self.user_active and sourcebuffer.get_modified() == True:
         self.update_window_save_needed()
      
   def file_save_as(self, *args):
      """Save the file providing a new name"""
      if self.tree_is_empty(): support.dialog_warning(_("The Tree is Empty!"), self.window)
      else:
         filepath = support.dialog_file_save_as(self.file_name,
                                                filter_pattern="*.ct*",
                                                filter_name=_("CherryTree Document"),
                                                curr_folder=self.file_dir,
                                                parent=self.window)
         if filepath != None:
            if not os.path.isfile(filepath)\
            or support.dialog_question(_("The File %s\nAlready Exists, do you want to Overwrite?") % filepath, self.window):
               filepath = self.filepath_extension_fix(filepath)
               if self.file_write(filepath):
                  self.file_dir = os.path.dirname(filepath)
                  self.file_name = os.path.basename(filepath)
                  support.add_recent_document(self, filepath)
                  self.update_window_save_not_needed()
                  self.state_machine.update_state(self.treestore[self.curr_tree_iter][3])
      
   def filepath_extension_fix(self, filepath):
      """Check a filepath to have the proper extension"""
      if not self.password:
         if len(filepath) < 4 or filepath[-4:] != ".ctd": return filepath + ".ctd"
      else:
         if len(filepath) < 4 or filepath[-4:] != ".ctz": return filepath + ".ctz"
      return filepath
      
   def file_save(self, *args):
      """Save the file"""
      if self.file_dir != "" and self.file_name != "":
         if self.tree_is_empty(): support.dialog_warning(_("The Tree is Empty!"), self.window)
         elif self.file_write(os.path.join(self.file_dir, self.file_name)):
            self.update_window_save_not_needed()
            self.state_machine.update_state(self.treestore[self.curr_tree_iter][3])
      else: self.file_save_as()
      
   def file_write_low_level(self, filepath, xml_string):
      """File Write Low Level (ctd or ctz)"""
      if self.password:
         if not os.path.isdir(cons.TMP_FOLDER): os.mkdir(cons.TMP_FOLDER)
         filepath_tmp = os.path.join(cons.TMP_FOLDER, os.path.basename(filepath[:-1] + "d"))
         file_descriptor = open(filepath_tmp, 'w')
      else: file_descriptor = open(filepath, 'w')
      file_descriptor.write(xml_string)
      file_descriptor.close()
      if self.password:
         if sys.platform[0:3] == "win":
            filepath_4win = support.windows_cmd_prepare_path(filepath)
            filepath_tmp_4win = support.windows_cmd_prepare_path(filepath_tmp)
            if not filepath_4win or not filepath_tmp_4win:
               support.dialog_error(_("The Contemporary Presence of Single and Double Quotes in the File Path Prevents 7za.exe to Work, Please Change the File Name"), self.window)
               raise
            bash_str = '7za a -p%s -bd -y ' % self.password +\
                       filepath_4win + cons.CHAR_SPACE + filepath_tmp_4win
         else:
            bash_str = '7za a -p%s -bd -y %s %s' % (self.password,
                                                    re.escape(filepath),
                                                    re.escape(filepath_tmp))
         #print bash_str
         ret_code = subprocess.call(bash_str, shell=True)
         #print ret_code
         os.remove(filepath_tmp)
      
   def file_write(self, filepath):
      """File Write"""
      try: xml_string = self.xml_handler.treestore_to_dom()
      except:
         support.dialog_error("%s write failed - tree to xml" % filepath, self.window)
         raise
         return False
      # backup before save new version
      if self.backup_copy:
         if os.path.isfile(filepath): shutil.move(filepath, filepath + cons.CHAR_TILDE)
      # if the filename is protected, we use unprotected type before compress and protect
      try:
         self.statusbar.push(self.statusbar_context_id, _("Writing to Disk..."))
         while gtk.events_pending(): gtk.main_iteration()
         self.file_write_low_level(filepath, xml_string)
         self.statusbar.pop(self.statusbar_context_id)
         return True
      except:
         support.dialog_error("%s write failed - writing to disk" % filepath, self.window)
         return False
      
   def file_open(self, *args):
      """Opens a dialog to browse for a cherrytree filepath"""
      filepath = support.dialog_file_select(filter_pattern="*.ct*",
                                            filter_name=_("CherryTree Document"),
                                            curr_folder=self.file_dir,
                                            parent=self.window)
      if filepath == None: return
      self.filepath_open(filepath)
      
   def filepath_open(self, filepath):
      """Opens an existing filepath"""
      if not self.reset(): return
      self.file_load(filepath)
      if self.expand_tree: self.treeview.expand_all()
      first_node_iter = self.treestore.get_iter_first()
      if first_node_iter != None:
         self.treeview.set_cursor(self.treestore.get_path(first_node_iter))
         self.sourceview.grab_focus()
      
   def dialog_edit_protection(self, *args):
      """Edit the Password for the Current Document"""
      if len(self.file_name) < 4:
         support.dialog_warning(_("No Document is Opened"), self.window)
         return
      edit_protection_dialog = gtk.Dialog(title=_("Document Protection"),
                                          parent=self.window,
                                          flags=gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
                                          buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
                                          gtk.STOCK_OK, gtk.RESPONSE_ACCEPT) )
      edit_protection_dialog.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
      radiobutton_unprotected = gtk.RadioButton(label=_("Not Protected"))
      radiobutton_protected = gtk.RadioButton(label=_("Password Protected"))
      radiobutton_protected.set_group(radiobutton_unprotected)
      entry_passw_1 = gtk.Entry()
      entry_passw_1.set_visibility(False)
      entry_passw_2 = gtk.Entry()
      entry_passw_2.set_visibility(False)
      vbox_passw = gtk.VBox()
      vbox_passw.pack_start(entry_passw_1)
      vbox_passw.pack_start(entry_passw_2)
      passw_frame = gtk.Frame(label="<b>"+_("Enter the New Password Twice")+"</b>")
      passw_frame.get_label_widget().set_use_markup(True)
      passw_frame.add(vbox_passw)
      if self.password:
         radiobutton_unprotected.set_active(False)
         radiobutton_protected.set_active(True)
         passw_frame.set_sensitive(True)
      else:
         radiobutton_unprotected.set_active(True)
         radiobutton_protected.set_active(False)
         passw_frame.set_sensitive(False)
      content_area = edit_protection_dialog.get_content_area()
      content_area.pack_start(radiobutton_unprotected)
      content_area.pack_start(radiobutton_protected)
      content_area.pack_start(passw_frame)
      content_area.show_all()
      def on_key_press_edit_protection_dialog(widget, event):
         if gtk.gdk.keyval_name(event.keyval) == "Return":
            button_box = edit_protection_dialog.get_action_area()
            buttons = button_box.get_children()
            buttons[0].clicked() # first is the ok button
      def on_radiobutton_protected_toggled(widget):
         passw_frame.set_sensitive(widget.get_active())
      radiobutton_protected.connect("toggled", on_radiobutton_protected_toggled)
      edit_protection_dialog.connect("key_press_event", on_key_press_edit_protection_dialog)
      response = edit_protection_dialog.run()
      new_protection = {'on':radiobutton_protected.get_active(),
                        'p1':entry_passw_1.get_text(),
                        'p2':entry_passw_2.get_text()}
      edit_protection_dialog.destroy()
      if response != gtk.RESPONSE_ACCEPT: return
      former_filename = self.file_name
      if new_protection['on']:
         if new_protection['p1'] == "":
            support.dialog_error(_("The Password Fields Must be Filled"), self.window)
            return
         if new_protection['p1'] != new_protection['p2']:
            support.dialog_error(_("The Two Inserted Passwords Do Not Match"), self.window)
            return
         if not self.password and not self.is_7za_available(): return
         self.password = new_protection['p1']
         self.file_name = self.file_name[:-1] + "z"
      else:
         self.password = None
         self.file_name = self.file_name[:-1] + "d"
      self.window.set_title(self.window.get_title().replace(former_filename, self.file_name))
      self.file_save()
      
   def is_7za_available(self):
      """Check 7za binary executable to be available"""
      ret_code = subprocess.call("7za", shell=True)
      if ret_code:
         support.dialog_error(_("Binary Executable '7za' Not Found, Check The Package 'p7zip-full' to be Installed Properly"), self.window)
         return False
      return True
      
   def dialog_insert_password(self, file_name):
      """Prompts a Dialog Asking for the File Password"""
      enter_password_dialog = gtk.Dialog(title=_("Enter Password for %s") % file_name,
                                         parent=self.window,
                                         flags=gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
                                         buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
                                         gtk.STOCK_OK, gtk.RESPONSE_ACCEPT) )
      enter_password_dialog.set_default_size(300, -1)
      enter_password_dialog.set_transient_for(self.window)
      enter_password_dialog.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
      entry = gtk.Entry()
      entry.set_visibility(False)
      content_area = enter_password_dialog.get_content_area()
      content_area.pack_start(entry)
      def on_key_press_enter_password_dialog(widget, event):
         if gtk.gdk.keyval_name(event.keyval) == "Return":
            button_box = enter_password_dialog.get_action_area()
            buttons = button_box.get_children()
            buttons[0].clicked() # first is the ok button
      enter_password_dialog.connect("key_press_event", on_key_press_enter_password_dialog)
      enter_password_dialog.show_all()
      if not sys.platform[0:3] == "win":
         the_window = enter_password_dialog.get_window()
         the_window.focus(gtk.gdk.x11_get_server_time(the_window))
      enter_password_dialog.present()
      response = enter_password_dialog.run()
      passw = entry.get_text()
      enter_password_dialog.destroy()
      while gtk.events_pending(): gtk.main_iteration()
      if response != gtk.RESPONSE_ACCEPT: return ""
      return passw
      
   def file_get_cherrytree_xml(self, filepath, main_file):
      """returns the cherrytree_string given the filepath"""
      password_protected = False
      if filepath[-1] == "z":
         password_protected = True
         password_str = self.dialog_insert_password(os.path.basename(filepath))
         if not password_str: return None
         if main_file: self.password = password_str
         if not self.is_7za_available(): return None
         if not os.path.isdir(cons.TMP_FOLDER): os.mkdir(cons.TMP_FOLDER)
         filepath_tmp = os.path.join(cons.TMP_FOLDER, os.path.basename(filepath[:-1] + "d"))
         if sys.platform[0:3] == "win":
            dest_dir_4win = support.windows_cmd_prepare_path("-o" + cons.TMP_FOLDER)
            filepath_4win = support.windows_cmd_prepare_path(filepath)
            if not dest_dir_4win or not filepath_4win:
               support.dialog_error(_("The Contemporary Presence of Single and Double Quotes in the File Path Prevents 7za.exe to Work, Please Change the File Name"), self.window)
               return None
            bash_str = '7za e -p%s -bd -y ' % password_str +\
                       dest_dir_4win + cons.CHAR_SPACE + filepath_4win
         else:
            bash_str = '7za e -p%s -bd -y -o%s %s' % (password_str,
                                                      re.escape(cons.TMP_FOLDER),
                                                      re.escape(filepath))
         #print bash_str
         ret_code = subprocess.call(bash_str, shell=True)
         if ret_code != 0:
            support.dialog_error(_('Wrong Password'), self.window)
            return None
      elif filepath[-1] != "d":
         print "bad filepath[-1]", filepath[-1]
         support.dialog_error(_('"%s" is Not a CherryTree Document') % filepath, self.window)
         return None
      elif main_file: self.password = None
      try:
         if password_protected: file_descriptor = open(filepath_tmp, 'r')
         else: file_descriptor = open(filepath, 'r')
         cherrytree_string = file_descriptor.read()
         file_descriptor.close()
         if password_protected: os.remove(filepath_tmp)
      except:
         support.dialog_error("Error opening the file %s" % filepath, self.window)
         return None
      return re.sub(cons.BAD_CHARS, "", cherrytree_string)
      
   def file_load(self, filepath):
      """Loads a .CTD into a GTK TreeStore"""
      cherrytree_string = self.file_get_cherrytree_xml(filepath, True)
      if not cherrytree_string:
         self.file_name = ""
         return
      self.user_active = False
      file_loaded = False
      try:
         if self.xml_handler.dom_to_treestore(cherrytree_string, discard_ids=False):
            self.file_dir = os.path.dirname(filepath)
            self.file_name = os.path.basename(filepath)
            support.add_recent_document(self, filepath)
            support.set_bookmarks_menu_items(self)
            self.update_window_save_not_needed()
            file_loaded = True
      except: raise
      if not file_loaded:
         support.dialog_error(_('"%s" is Not a CherryTree Document') % filepath, self.window)
         self.file_name = ""
      self.user_active = True
      
   def file_new(self, *args):
      """Starts a new unsaved instance"""
      if self.reset(): self.node_add()
      
   def reset(self):
      """Reset the Application"""
      if not self.tree_is_empty() and not self.check_unsaved(): return False
      if self.curr_tree_iter != None:
         self.curr_buffer.set_text("")
         self.curr_tree_iter = None
      self.treestore.clear()
      self.file_name = ""
      self.password = None
      self.node_id_counter = long(0)
      self.update_window_save_not_needed()
      self.state_machine.reset()
      self.sourceview.set_sensitive(False)
      return True
      
   def export_to_ctd(self, action):
      """Export the Selected Node and its Subnodes"""
      if self.curr_tree_iter == None:
         support.dialog_warning(_("No Node is Selected!"), self.window)
         return
      export_type = support.dialog_selnode_selnodeandsub_alltree(self.window)
      if export_type == 0: return
      ctd_handler = exports.Export2CTD(self)
      if self.password: filter_pattern = "*.ctz"
      else: filter_pattern = "*.ctd"
      if export_type == 1:
         # only selected node
         proposed_name = support.get_node_hierarchical_name(self, self.curr_tree_iter)
         if self.password: proposed_name += ".ctz"
         else: proposed_name += ".ctd"
         ctd_filepath = ctd_handler.get_single_ctd_filepath(proposed_name, filter_pattern)
         if ctd_filepath:
            ctd_handler.node_export_to_ctd(self.curr_tree_iter, ctd_filepath)
      elif export_type == 2:
         # selected node and subnodes
         proposed_name = support.get_node_hierarchical_name(self, self.curr_tree_iter)
         if self.password: proposed_name += ".ctz"
         else: proposed_name += ".ctd"
         ctd_filepath = ctd_handler.get_single_ctd_filepath(proposed_name, filter_pattern)
         if ctd_filepath:
            ctd_handler.node_and_subnodes_export_to_ctd(self.curr_tree_iter, ctd_filepath)
      else:
         # all nodes
         proposed_name = self.file_name
         ctd_filepath = ctd_handler.get_single_ctd_filepath(proposed_name, filter_pattern)
         if ctd_filepath:
            ctd_handler.nodes_all_export_to_ctd(ctd_filepath)
      
   def export_to_txt(self, *args):
      """Export To Plain Text"""
      if self.curr_tree_iter == None:
         support.dialog_warning(_("No Node is Selected!"), self.window)
         return
      export_type = support.dialog_selnode_selnodeandsub_alltree(self.window)
      if export_type == 0: return
      txt_handler = exports.Export2Txt(self)
      if export_type == 1:
         # only selected node
         proposed_name = support.get_node_hierarchical_name(self, self.curr_tree_iter)
         txt_filepath = txt_handler.get_single_txt_filepath(proposed_name)
         if txt_filepath:
            txt_handler.node_export_to_txt(self.curr_buffer, txt_filepath)
      elif export_type == 2:
         # selected node and subnodes
         folder_name = support.get_node_hierarchical_name(self, self.curr_tree_iter)
         if txt_handler.prepare_txt_folder(folder_name):
            txt_handler.nodes_all_export_to_txt(self.curr_tree_iter)
      else:
         # all nodes
         if txt_handler.prepare_txt_folder(self.file_name):
            txt_handler.nodes_all_export_to_txt()
      
   def export_to_html(self, *args):
      """Export to HTML"""
      if self.curr_tree_iter == None:
         support.dialog_warning(_("No Node is Selected!"), self.window)
         return
      export_type = support.dialog_selnode_selnodeandsub_alltree(self.window)
      if export_type == 0: return
      if export_type == 1:
         # only selected node
         folder_name = support.get_node_hierarchical_name(self, self.curr_tree_iter)
         if self.html_handler.prepare_html_folder(folder_name):
            self.html_handler.node_export_to_html(self.curr_tree_iter)
      elif export_type == 2:
         # selected node and subnodes
         folder_name = support.get_node_hierarchical_name(self, self.curr_tree_iter)
         if self.html_handler.prepare_html_folder(folder_name):
            self.html_handler.nodes_all_export_to_html(self.curr_tree_iter)
      else:
         # all nodes
         if self.html_handler.prepare_html_folder(self.file_name):
            self.html_handler.nodes_all_export_to_html()
      
   def export_print_page_setup(self, action):
      """Print Page Setup Operations"""
      if self.print_handler.settings is None:
         self.print_handler.settings = gtk.PrintSettings()
      self.print_handler.page_setup = gtk.print_run_page_setup_dialog(self.glade.window,
                                                                      self.print_handler.page_setup,
                                                                      self.print_handler.settings)
      
   def export_print(self, action):
      """Start Print Operations"""
      if not self.curr_tree_iter:
         support.dialog_warning(_("No Node is Selected!"), self.window)
         return
      export_type = support.dialog_selnode_selnodeandsub_alltree(self.window)
      if export_type == 0: return
      pdf_handler = exports.ExportPrint(self)
      if export_type == 1:
         # only selected node
         pdf_handler.node_export_print(self.curr_tree_iter)
      elif export_type == 2:
         # selected node and subnodes
         pdf_handler.nodes_all_export_print(self.curr_tree_iter)
      else:
         # all nodes
         pdf_handler.nodes_all_export_print()
   
   def tree_sort_level_and_sublevels(self, model, father_iter, ascending):
      """Sorts the Tree Level and All the Sublevels"""
      movements = False
      while self.node_siblings_sort_iteration(model, father_iter, ascending, 1):
         movements = True
      if father_iter: curr_sibling = model.iter_children(father_iter)
      else: curr_sibling = model.get_iter_first()
      while curr_sibling:
         if self.tree_sort_level_and_sublevels(model, curr_sibling, ascending): movements = True
         curr_sibling = model.iter_next(curr_sibling)
      return movements
   
   def tree_sort_ascending(self, *args):
      """Sorts the Tree Ascending"""
      if self.tree_sort_level_and_sublevels(self.treestore, None, True): self.update_window_save_needed()
      
   def tree_sort_descending(self, *args):
      """Sorts the Tree Descending"""
      if self.tree_sort_level_and_sublevels(self.treestore, None, False): self.update_window_save_needed()
   
   def node_siblings_sort_ascending(self, *args):
      """Sorts all the Siblings of the Selected Node Ascending"""
      if not self.curr_tree_iter:
         support.dialog_warning(_("No Node is Selected!"), self.window)
         return
      father_iter = self.treestore.iter_parent(self.curr_tree_iter)
      movements = False
      while self.node_siblings_sort_iteration(self.treestore, father_iter, True, 1):
         movements = True
      if movements: self.update_window_save_needed()
      
   def node_siblings_sort_descending(self, *args):
      """Sorts all the Siblings of the Selected Node Descending"""
      if not self.curr_tree_iter:
         support.dialog_warning(_("No Node is Selected!"), self.window)
         return
      father_iter = self.treestore.iter_parent(self.curr_tree_iter)
      movements = False
      while self.node_siblings_sort_iteration(self.treestore, father_iter, False, 1):
         movements = True
      if movements: self.update_window_save_needed()
      
   def node_siblings_sort_iteration(self, model, father_iter, ascending, column):
      """Runs One Sorting Iteration, Returns True if Any Swap was Necessary"""
      if father_iter: curr_sibling = model.iter_children(father_iter)
      else: curr_sibling = model.get_iter_first()
      if not curr_sibling: return False
      next_sibling = model.iter_next(curr_sibling)
      swap_executed = False
      while next_sibling != None:
         if (ascending and model[next_sibling][column].lower() < model[curr_sibling][column].lower())\
         or (not ascending and model[next_sibling][column].lower() > model[curr_sibling][column].lower()):
            model.swap(next_sibling, curr_sibling)
            swap_executed = True
         else: curr_sibling = next_sibling
         next_sibling = model.iter_next(curr_sibling)
      return swap_executed
   
   def node_inherit_syntax(self, *args):
      """Change the Selected Node's Children Syntax Highlighting to the Father's Syntax Highlighting"""
      if self.curr_tree_iter == None:
         support.dialog_warning(_("No Node is Selected!"), self.window)
         return
      self.node_inherit_syntax_iter(self.curr_tree_iter)
      self.sourceview.set_buffer(self.treestore[self.curr_tree_iter][2])
      
   def node_inherit_syntax_iter(self, iter_father):
      """Iteration of the Node Inherit Syntax"""
      iter_child = self.treestore.iter_children(iter_father)
      while iter_child != None:
         if self.treestore[iter_child][4] != self.treestore[iter_father][4]:
            self.treestore[iter_child][4] = self.treestore[iter_father][4]
            self.treestore[iter_child][0] = self.get_node_icon(self.treestore[iter_child][5],
                                                               self.treestore[iter_child][4])
            self.switch_buffer_text_source(self.treestore[iter_child][2],
                                           iter_child,
                                           self.treestore[iter_child][4])
            if self.treestore[iter_child][4] != cons.CUSTOM_COLORS_ID:
               self.set_sourcebuffer_syntax_highlight(self.treestore[iter_child][2],
                                                      self.treestore[iter_child][4])
            self.update_window_save_needed()
         self.node_inherit_syntax_iter(iter_child)
         iter_child = self.treestore.iter_next(iter_child)
   
   def node_up(self, *args):
      """Node up one position"""
      if self.curr_tree_iter == None:
         support.dialog_warning(_("No Node is Selected!"), self.window)
         return
      prev_iter = self.get_tree_iter_prev_sibling(self.treestore, self.curr_tree_iter)
      if prev_iter != None:
         self.treestore.swap(self.curr_tree_iter, prev_iter)
         self.treeview.set_cursor(self.treestore.get_path(self.curr_tree_iter))
         self.update_window_save_needed()
      
   def node_down(self, *args):
      """Node down one position"""
      if self.curr_tree_iter == None:
         support.dialog_warning(_("No Node is Selected!"), self.window)
         return
      subseq_iter = self.treestore.iter_next(self.curr_tree_iter)
      if subseq_iter != None:
         self.treestore.swap(self.curr_tree_iter, subseq_iter)
         self.treeview.set_cursor(self.treestore.get_path(self.curr_tree_iter))
         self.update_window_save_needed()
   
   def node_left(self, *args):
      """Node left one position"""
      if self.curr_tree_iter == None:
         support.dialog_warning(_("No Node is Selected!"), self.window)
         return
      father_iter = self.treestore.iter_parent(self.curr_tree_iter)
      if father_iter != None:
         self.node_move_after(self.curr_tree_iter,
                              self.treestore.iter_parent(father_iter),
                              father_iter)
         if self.nodes_icons == "c": self.treeview_refresh(change_icon=True)
   
   def node_move_after(self, iter_to_move, father_iter, brother_iter=None, set_first=False):
      """Move a node to a father and after a brother"""
      if brother_iter != None:
         new_node_iter = self.treestore.insert_after(father_iter, brother_iter, self.treestore[iter_to_move])
      elif set_first: new_node_iter = self.treestore.prepend(father_iter, self.treestore[iter_to_move])
      else: new_node_iter = self.treestore.append(father_iter, self.treestore[iter_to_move])
      # we move also all the children
      self.node_move_children(iter_to_move, new_node_iter)
      # now we can remove the old iter (and all children)
      self.treestore.remove(iter_to_move)
      if father_iter != None: self.treeview.expand_row(self.treestore.get_path(father_iter), True)
      else: self.treeview.expand_row(self.treestore.get_path(new_node_iter), True)
      self.curr_tree_iter = new_node_iter
      self.treeview.set_cursor(self.treestore.get_path(new_node_iter))
      self.update_window_save_needed()
   
   def node_move_children(self, old_father, new_father):
      """Move the children from a father to another"""
      children_iter_to_move = self.treestore.iter_children(old_father)
      while children_iter_to_move != None:
         new_children_iter = self.treestore.append(new_father, self.treestore[children_iter_to_move])
         self.node_move_children(children_iter_to_move, new_children_iter)
         children_iter_to_move = self.treestore.iter_next(children_iter_to_move)
   
   def node_change_father(self, *args):
      """Node browse for a new father"""
      if self.curr_tree_iter == None:
         support.dialog_warning(_("No Node is Selected!"), self.window)
         return
      curr_node_id = self.treestore[self.curr_tree_iter][3]
      old_father_iter = self.treestore.iter_parent(self.curr_tree_iter)
      if old_father_iter != None: old_father_node_id = self.treestore[old_father_iter][3]
      else: old_father_node_id = None
      self.node_choose_view_exist_or_create()
      self.glade.link_dialog_top_vbox.hide()
      self.glade.frame_link_anchor.hide()
      self.glade.choosenodedialog.set_title(_("Select the New Father"))
      self.glade.hbox_link_node_anchor.set_sensitive(True)
      response = self.glade.choosenodedialog.run()
      self.glade.choosenodedialog.hide()
      if response != 1: return # the user aborted the operation
      model, father_iter = self.treeviewselection_2.get_selected()
      new_father_node_id = self.treestore[father_iter][3]
      if curr_node_id == new_father_node_id:
         support.dialog_error(_("The new father can't be the very node to move!"), self.window)
         return
      if old_father_node_id != None and new_father_node_id == old_father_node_id:
         support.dialog_info(_("The new choosed father is again the old father!"), self.window)
         return
      move_towards_top_iter = self.treestore.iter_parent(father_iter)
      while move_towards_top_iter:
         if self.treestore[move_towards_top_iter][3] == curr_node_id:
            support.dialog_error(_("The new father can't be one of his sons!"), self.window)
            return
         move_towards_top_iter = self.treestore.iter_parent(move_towards_top_iter)
      self.node_move_after(self.curr_tree_iter, father_iter)
      if self.nodes_icons == "c": self.treeview_refresh(change_icon=True)
   
   def node_choose_view_exist_or_create(self, node_sel_id=None):
      """If The View Was Never Used, this will Create It"""
      if "treeview_2" not in dir(self):
         self.treeview_2 = gtk.TreeView(self.treestore)
         self.treeview_2.set_headers_visible(False)
         self.renderer_pixbuf_2 = gtk.CellRendererPixbuf()
         self.renderer_text_2 = gtk.CellRendererText()
         self.column_2 = gtk.TreeViewColumn()
         self.column_2.pack_start(self.renderer_pixbuf_2, False)
         self.column_2.pack_start(self.renderer_text_2, True)
         self.column_2.set_attributes(self.renderer_pixbuf_2, stock_id=0)
         self.column_2.set_attributes(self.renderer_text_2, text=1)
         self.treeview_2.append_column(self.column_2)
         self.treeviewselection_2 = self.treeview_2.get_selection()
         self.treeview_2.connect('button-press-event', self.on_mouse_button_clicked_treeview_2)
         self.glade.scrolledwindow_choosenode.add(self.treeview_2)
         self.glade.scrolledwindow_choosenode.show_all()
      if node_sel_id == None:
         self.treeview_2.set_cursor(self.treestore.get_path(self.curr_tree_iter))
      else:
         tree_iter_sel = self.get_tree_iter_from_node_id(node_sel_id)
         if tree_iter_sel != None: self.treeview_2.set_cursor(self.treestore.get_path(tree_iter_sel))
         
   def on_mouse_button_clicked_treeview_2(self, widget, event):
      """Catches mouse buttons clicks"""
      if event.button != 1: return
      if event.type == gtk.gdk._2BUTTON_PRESS: self.glade.choosenodedialog_button_ok.clicked()
         
   def get_tree_iter_from_node_id(self, node_id):
      """Given a Node Id, Returns the TreeIter or None"""
      tree_iter = self.treestore.get_iter_first()
      while tree_iter != None:
         if self.treestore[tree_iter][3] == node_id: return tree_iter
         child_tree_iter = self.get_tree_iter_from_node_id_children(tree_iter, node_id)
         if child_tree_iter != None: return child_tree_iter
         tree_iter = self.treestore.iter_next(tree_iter)
      return None
   
   def get_tree_iter_from_node_id_children(self, father_iter, node_id):
      """Iterative function searching for Node Id between Children"""
      tree_iter = self.treestore.iter_children(father_iter)
      while tree_iter != None:
         if self.treestore[tree_iter][3] == node_id: return tree_iter
         child_tree_iter = self.get_tree_iter_from_node_id_children(tree_iter, node_id)
         if child_tree_iter != None: return child_tree_iter
         tree_iter = self.treestore.iter_next(tree_iter)
      return None
         
   def get_tree_iter_from_node_name(self, node_name):
      """Given a Node Id, Returns the TreeIter or None"""
      tree_iter = self.treestore.get_iter_first()
      while tree_iter != None:
         if self.treestore[tree_iter][1] == node_name: return tree_iter
         child_tree_iter = self.get_tree_iter_from_node_name_children(tree_iter, node_name)
         if child_tree_iter != None: return child_tree_iter
         tree_iter = self.treestore.iter_next(tree_iter)
      return None
   
   def get_tree_iter_from_node_name_children(self, father_iter, node_name):
      """Iterative function searching for Node Id between Children"""
      tree_iter = self.treestore.iter_children(father_iter)
      while tree_iter != None:
         if self.treestore[tree_iter][1] == node_name: return tree_iter
         child_tree_iter = self.get_tree_iter_from_node_name_children(tree_iter, node_name)
         if child_tree_iter != None: return child_tree_iter
         tree_iter = self.treestore.iter_next(tree_iter)
      return None
   
   def treeview_safe_set_cursor(self, tree_iter):
      """Set Cursor being sure the Node is Expanded"""
      nodes_to_expand = []
      father_iter = self.treestore.iter_parent(tree_iter)
      while father_iter:
         nodes_to_expand.insert(0, father_iter)
         father_iter = self.treestore.iter_parent(father_iter)
      for element_iter in nodes_to_expand:
         self.treeview.expand_row(self.treestore.get_path(element_iter), open_all=False)
      self.treeview.set_cursor(self.treestore.get_path(tree_iter))
   
   def on_table_column_rename_radiobutton_toggled(self, radiobutton):
      """Table Column Rename Toggled"""
      if radiobutton.get_active():
         self.glade.table_column_rename_entry.set_sensitive(True)
         self.table_column_mode = "rename"
      else: self.glade.table_column_rename_entry.set_sensitive(False)
      
   def on_table_column_delete_radiobutton_toggled(self, radiobutton):
      """Table Column Delete Toggled"""
      if radiobutton.get_active(): self.table_column_mode = "delete"
      
   def on_table_column_add_radiobutton_toggled(self, radiobutton):
      """Table Column Delete Toggled"""
      if radiobutton.get_active():
         self.glade.table_column_new_entry.set_sensitive(True)
         self.table_column_mode = "add"
      else: self.glade.table_column_new_entry.set_sensitive(False)
      
   def on_table_column_left_radiobutton_toggled(self, radiobutton):
      """Table Column Left Toggled"""
      if radiobutton.get_active(): self.table_column_mode = "left"
      
   def on_table_column_right_radiobutton_toggled(self, radiobutton):
      """Table Column Right Toggled"""
      if radiobutton.get_active(): self.table_column_mode = "right"
   
   def on_help_menu_item_activated(self, menuitem, data=None):
      """Show the application's Home Page"""
      webbrowser.open("http://www.giuspen.com/cherrytree/")
   
   def on_spinbutton_tab_width_value_changed(self, spinbutton):
      """Tabs Width (in chars) Change Handling"""
      self.tabs_width = int(spinbutton.get_value())
      self.sourceview.set_tab_width(self.tabs_width)
      
   def on_spinbutton_tree_nodes_names_width_value_changed(self, spinbutton):
      """Cherry Wrap Width Change Handling"""
      self.cherry_wrap_width = int(spinbutton.get_value())
      self.renderer_text.set_property('wrap-width', self.cherry_wrap_width)
      self.treeview_refresh()
      
   def on_checkbutton_custom_weblink_cmd_toggled(self, checkbutton):
      """Custom Web Link Clicked Action Toggled Handling"""
      if checkbutton.get_active(): self.weblink_custom_action[0] = True
      else: self.weblink_custom_action[0] = False
      self.glade.entry_custom_weblink_cmd.set_sensitive(self.weblink_custom_action[0])
      
   def on_entry_custom_weblink_cmd_changed(self, entry):
      """Custom Web Link Clicked Action Edited"""
      self.weblink_custom_action[1] = entry.get_text()
      
   def on_checkbutton_custom_filelink_cmd_toggled(self, checkbutton):
      """Custom File Link Clicked Action Toggled Handling"""
      if checkbutton.get_active(): self.filelink_custom_action[0] = True
      else: self.filelink_custom_action[0] = False
      self.glade.entry_custom_filelink_cmd.set_sensitive(self.filelink_custom_action[0])
      
   def on_entry_custom_filelink_cmd_changed(self, entry):
      """Custom File Link Clicked Action Edited"""
      self.filelink_custom_action[1] = entry.get_text()
      
   def on_checkbutton_custom_folderlink_cmd_toggled(self, checkbutton):
      """Custom Folder Link Clicked Action Toggled Handling"""
      if checkbutton.get_active(): self.folderlink_custom_action[0] = True
      else: self.folderlink_custom_action[0] = False
      self.glade.entry_custom_folderlink_cmd.set_sensitive(self.folderlink_custom_action[0])
      
   def on_entry_custom_folderlink_cmd_changed(self, entry):
      """Custom Folder Link Clicked Action Edited"""
      self.folderlink_custom_action[1] = entry.get_text()
      
   def on_checkbutton_systray_toggled(self, checkbutton):
      """SysTray Toggled Handling"""
      if not self.user_active: return
      self.systray = checkbutton.get_active()
      if self.systray:
         if "status_icon" in dir(self): self.status_icon.set_property('visible', True)
         else: self.status_icon_enable()
         self.ui.get_widget("/MenuBar/FileMenu/ExitApp").set_property('visible', True)
         self.glade.checkbutton_start_on_systray.set_sensitive(True)
      else:
         self.status_icon.set_property('visible', False)
         self.ui.get_widget("/MenuBar/FileMenu/ExitApp").set_property('visible', False)
         self.glade.checkbutton_start_on_systray.set_sensitive(False)
      
   def on_checkbutton_start_on_systray_toggled(self, checkbutton):
      """Start Minimized on SysTray Toggled Handling"""
      if checkbutton.get_active(): self.start_on_systray = True
      else: self.start_on_systray = False
      
   def on_checkbutton_autosave_toggled(self, checkbutton):
      """Autosave Toggled Handling"""
      self.autosave[0] = checkbutton.get_active()
      if not self.autosave[0] and self.autosave_timer_id != None: self.autosave_timer_stop()
      self.glade.spinbutton_autosave.set_sensitive(self.autosave[0])
      
   def on_checkbutton_line_wrap_toggled(self, checkbutton):
      """Lines Wrapping Toggled Handling"""
      self.line_wrapping = checkbutton.get_active()
      if self.line_wrapping: self.sourceview.set_wrap_mode(gtk.WRAP_WORD)
      else: self.sourceview.set_wrap_mode(gtk.WRAP_NONE)
      
   def on_checkbutton_spaces_tabs_toggled(self, checkbutton):
      """Insert Spaces Instead of Tabs Toggled Handling"""
      self.spaces_instead_tabs = checkbutton.get_active()
      self.sourceview.set_insert_spaces_instead_of_tabs(self.spaces_instead_tabs)
   
   def on_checkbutton_auto_indent_toggled(self, checkbutton):
      """Automatic Indentation Toggled Handling"""
      self.auto_indent = self.glade.checkbutton_auto_indent.get_active()
      self.sourceview.set_auto_indent(self.auto_indent)
   
   def on_checkbutton_line_nums_toggled(self, checkbutton):
      """Show Line Num Toggled Handling"""
      self.show_line_numbers = checkbutton.get_active()
      self.sourceview.set_show_line_numbers(self.show_line_numbers)
      
   def on_checkbutton_expand_tree_toggled(self, checkbutton):
      """Expand Tree When Loaded Toggled"""
      self.expand_tree = checkbutton.get_active()
      
   def on_checkbutton_newer_version_toggled(self, checkbutton):
      """Automatically Check for Newer Version Toggled"""
      self.check_version = checkbutton.get_active()
   
   def on_checkbutton_backup_before_saving_toggled(self, checkbutton):
      """Backup Before Save Toggled"""
      self.backup_copy = checkbutton.get_active()
   
   def on_checkbutton_autosave_on_quit_toggled(self, checkbutton):
      """Autosave on Quit Toggled"""
      self.autosave_on_quit = checkbutton.get_active()
   
   def on_checkbutton_tree_right_side_toggled(self, checkbutton):
      """Display Tree on the Right Side Toggled"""
      if not self.user_active: return
      self.tree_right_side = checkbutton.get_active()
      tree_width = self.scrolledwindow_tree.get_allocation().width
      text_width = self.vbox_text.get_allocation().width
      self.hpaned.remove(self.scrolledwindow_tree)
      self.hpaned.remove(self.vbox_text)
      if self.tree_right_side:
         self.hpaned.add1(self.vbox_text)
         self.hpaned.add2(self.scrolledwindow_tree)
         self.hpaned.set_property('position', text_width)
      else:
         self.hpaned.add1(self.scrolledwindow_tree)
         self.hpaned.add2(self.vbox_text)
         self.hpaned.set_property('position', tree_width)
      
   def on_checkbutton_table_ins_from_file_toggled(self, checkbutton):
      """Import Table from CSV File Toggled"""
      self.glade.tablehandle_frame_table.set_sensitive(not checkbutton.get_active())
      self.glade.tablehandle_frame_col.set_sensitive(not checkbutton.get_active())
      
   def on_radiobutton_link_website_toggled(self, radiobutton):
      """Show/Hide Relative Frames"""
      if radiobutton.get_active(): self.link_type = "webs"
      self.link_type_changed_on_dialog()
      
   def on_radiobutton_link_node_anchor_toggled(self, checkbutton):
      """Show/Hide Relative Frames"""
      if checkbutton.get_active(): self.link_type = "node"
      self.link_type_changed_on_dialog()
      
   def on_radiobutton_link_file_toggled(self, radiobutton):
      """Show/Hide Relative Frames"""
      if radiobutton.get_active(): self.link_type = "file"
      self.link_type_changed_on_dialog()
   
   def on_radiobutton_link_folder_toggled(self, radiobutton):
      """Show/Hide Relative Frames"""
      if radiobutton.get_active(): self.link_type = "fold"
      self.link_type_changed_on_dialog()
   
   def link_type_changed_on_dialog(self):
      """Change the Graphic of the Dialog according to the New Link Type"""
      self.glade.frame_link_website_url.set_sensitive(self.link_type == "webs")
      self.glade.hbox_link_node_anchor.set_sensitive(self.link_type == "node")
      self.glade.frame_link_filepath.set_sensitive(self.link_type in ["file", "fold"])
   
   def on_radiobutton_node_icon_cherry_toggled(self, radiobutton):
      """Change Variable Value Accordingly"""
      if radiobutton.get_active():
         self.nodes_icons = "c"
         if self.user_active: self.treeview_refresh(change_icon=True)
   
   def on_radiobutton_node_icon_bullet_toggled(self, radiobutton):
      """Change Variable Value Accordingly"""
      if radiobutton.get_active():
         self.nodes_icons = "b"
         if self.user_active: self.treeview_refresh(change_icon=True)
   
   def on_radiobutton_node_icon_none_toggled(self, radiobutton):
      """Change Variable Value Accordingly"""
      if radiobutton.get_active():
         self.nodes_icons = "n"
         if self.user_active: self.treeview_refresh(change_icon=True)
   
   def on_mouse_button_clicked_tree(self, widget, event):
      """Catches mouse buttons clicks"""
      if event.button == 3:
         self.menu_tree.popup(None, None, None, event.button, event.time)
      elif event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS:
         self.node_edit()
      
   def buffer_create(self, syntax_highlighting):
      """Returns a New Instantiated SourceBuffer"""
      if syntax_highlighting != cons.CUSTOM_COLORS_ID:
         buffer = gtksourceview2.Buffer()
         self.set_sourcebuffer_syntax_highlight(buffer, syntax_highlighting)
         buffer.set_highlight_matching_brackets(True)
         return buffer
      else: return gtk.TextBuffer(self.tag_table)
      
   def combobox_prog_lang_init(self):
      """Init The Programming Languages Syntax Highlighting"""
      self.prog_lang_liststore = gtk.ListStore(str, str)
      self.prog_lang_liststore.append([_("Disabled (Custom Colors)"), cons.CUSTOM_COLORS_ID])
      self.language_manager = gtksourceview2.LanguageManager()
      self.available_languages = self.language_manager.get_language_ids()
      if "def" in self.available_languages: self.available_languages.remove("def")
      for language_id in sorted(self.available_languages):
         self.prog_lang_liststore.append([self.language_manager.get_language(language_id).get_name(), language_id])
      for combobox in [self.glade.combobox_prog_lang, self.glade.combobox_prog_lang_codebox]:
         combobox.set_model(self.prog_lang_liststore)
         cell = gtk.CellRendererText()
         combobox.pack_start(cell, True)
         combobox.add_attribute(cell, 'text', 0)
         combobox.set_active_iter(self.get_combobox_prog_lang_iter(self.syntax_highlighting))
   
   def get_combobox_prog_lang_iter(self, prog_language):
      """Returns the Language iter Given the Language Name"""
      curr_iter = self.prog_lang_liststore.get_iter_first()
      while curr_iter != None:
         if self.prog_lang_liststore[curr_iter][1] == prog_language: break
         else: curr_iter = self.prog_lang_liststore.iter_next(curr_iter)
      else: return self.prog_lang_liststore.get_iter_first()
      return curr_iter
   
   def on_combobox_country_language_changed(self, combobox):
      """New Country Language Choosed"""
      new_iter = self.glade.combobox_country_language.get_active_iter()
      new_lang = self.country_lang_liststore[new_iter][0]
      if new_lang != self.country_lang:
         self.country_lang = new_lang
         support.dialog_info(_("The New Language will be Available Only After Restarting CherryTree"), self.window)
         lang_file_descriptor = file(cons.LANG_PATH, 'w')
         lang_file_descriptor.write(new_lang)
         lang_file_descriptor.close()
   
   def combobox_country_lang_init(self):
      """Init The Programming Languages Syntax Highlighting"""
      combobox = self.glade.combobox_country_language
      self.country_lang_liststore = gtk.ListStore(str)
      combobox.set_model(self.country_lang_liststore)
      cell = gtk.CellRendererText()
      combobox.pack_start(cell, True)
      combobox.add_attribute(cell, 'text', 0)
      for country_lang in cons.AVAILABLE_LANGS:
         self.country_lang_liststore.append([country_lang])
      combobox.set_active_iter(self.get_combobox_country_lang_iter(self.country_lang))
      self.glade.combobox_country_language.connect('changed', self.on_combobox_country_language_changed)
   
   def get_combobox_country_lang_iter(self, country_language):
      """Returns the Language iter Given the Language Name"""
      curr_iter = self.country_lang_liststore.get_iter_first()
      while curr_iter != None:
         if self.country_lang_liststore[curr_iter][0] == country_language: break
         else: curr_iter = self.country_lang_liststore.iter_next(curr_iter)
      else: return self.country_lang_liststore.get_iter_first()
      return curr_iter
      
   def set_sourcebuffer_syntax_highlight(self, sourcebuffer, syntax_highlighting):
      """Set the given syntax highlighting to the given sourcebuffer"""
      language_id = self.prog_lang_liststore[self.get_combobox_prog_lang_iter(syntax_highlighting)][1]
      sourcebuffer.set_language(self.language_manager.get_language(language_id))
      sourcebuffer.set_highlight_syntax(True)
      
   def node_add(self, *args):
      """Add a node having common father with the selected node's"""
      self.glade.checkbutton_readonly.set_active(False)
      node_name = self.dialog_input(title=_("Insert the New Node Name..."), syntax_highlight=True)
      if node_name == None: return
      self.update_window_save_needed()
      self.syntax_highlighting = self.prog_lang_liststore[self.glade.combobox_prog_lang.get_active_iter()][1]
      if self.curr_tree_iter == None: node_level = 0
      else: node_level = self.treestore[self.curr_tree_iter][5]
      cherry = self.get_node_icon(node_level, self.syntax_highlighting)
      if self.curr_tree_iter != None:
         new_node_iter = self.treestore.insert_after(self.treestore.iter_parent(self.curr_tree_iter), 
                                                     self.curr_tree_iter, [cherry,
                                                                           node_name,
                                                                           self.buffer_create(self.syntax_highlighting),
                                                                           self.node_id_get(),
                                                                           self.syntax_highlighting,
                                                                           node_level,
                                                                           self.glade.tags_searching_entry.get_text(),
                                                                           self.glade.checkbutton_readonly.get_active()])
      else:
         new_node_iter = self.treestore.append(None, [cherry,
                                                      node_name,
                                                      self.buffer_create(self.syntax_highlighting),
                                                      self.node_id_get(),
                                                      self.syntax_highlighting,
                                                      node_level,
                                                      self.glade.tags_searching_entry.get_text(),
                                                      self.glade.checkbutton_readonly.get_active()])
      self.nodes_names_dict[self.treestore[new_node_iter][3]] = self.treestore[new_node_iter][1]
      new_node_path = self.treestore.get_path(new_node_iter)
      self.treeview.set_cursor(new_node_path)
      self.sourceview.grab_focus()
      
   def node_child_add(self, *args):
      """Add a node having as father the selected node"""
      if self.curr_tree_iter == None:
         support.dialog_warning(_("No Node is Selected!"), self.window)
         return
      self.glade.checkbutton_readonly.set_active(False)
      node_name = self.dialog_input(title=_("Insert the New Child Node Name..."), syntax_highlight=True)
      if node_name != None:
         self.update_window_save_needed()
         self.syntax_highlighting = self.prog_lang_liststore[self.glade.combobox_prog_lang.get_active_iter()][1]
         if self.curr_tree_iter == None: node_level = 0
         else: node_level = self.treestore[self.curr_tree_iter][5] + 1
         cherry = self.get_node_icon(node_level, self.syntax_highlighting)
         new_node_iter = self.treestore.append(self.curr_tree_iter, [cherry,
                                                                     node_name,
                                                                     self.buffer_create(self.syntax_highlighting),
                                                                     self.node_id_get(),
                                                                     self.syntax_highlighting,
                                                                     node_level,
                                                                     self.glade.tags_searching_entry.get_text(),
                                                                     self.glade.checkbutton_readonly.get_active()])
         self.nodes_names_dict[self.treestore[new_node_iter][3]] = self.treestore[new_node_iter][1]
         new_node_path = self.treestore.get_path(new_node_iter)
         father_node_path = self.treestore.get_path(self.curr_tree_iter)
         self.treeview.expand_row(father_node_path, True) # second parameter tells whether to expand childrens too
         self.treeview.set_cursor(new_node_path)
         self.sourceview.grab_focus()
         
   def node_delete(self, *args):
      """Delete the Selected Node"""
      if self.curr_tree_iter == None:
         support.dialog_warning(_("No Node is Selected!"), self.window)
         return
      warning_label = _("Are you sure to <b>Delete the node '%s'?</b>") % self.treestore[self.curr_tree_iter][1]
      if self.treestore.iter_children(self.curr_tree_iter) != None:
         warning_label += _("\n\nThe node <b>has Children, they will be Deleted too!</b>")
      self.glade.label_node_delete.set_text(warning_label)
      self.glade.label_node_delete.set_use_markup(True)
      response = self.glade.nodedeletedialog.run()
      self.glade.nodedeletedialog.hide()
      if response != 1: return # the user did not confirm
      # next selected node will be previous sibling or next sibling or father or None
      new_iter = self.get_tree_iter_prev_sibling(self.treestore, self.curr_tree_iter)
      if new_iter == None:
         new_iter = self.treestore.iter_next(self.curr_tree_iter)
         if new_iter == None: new_iter = self.treestore.iter_parent(self.curr_tree_iter)
      self.treestore.remove(self.curr_tree_iter)
      self.curr_tree_iter = None
      if new_iter != None:
         self.treeview.set_cursor(self.treestore.get_path(new_iter))
         self.sourceview.grab_focus()
      self.update_window_save_needed()
         
   def node_edit(self, *args):
      """Edit the Properties of the Selected Node"""
      if self.curr_tree_iter == None:
         support.dialog_warning(_("No Node is Selected!"), self.window)
         return
      self.glade.combobox_prog_lang.set_active_iter(self.get_combobox_prog_lang_iter(self.treestore[self.curr_tree_iter][4]))
      self.glade.tags_searching_entry.set_text(self.treestore[self.curr_tree_iter][6])
      self.glade.checkbutton_readonly.set_active(self.treestore[self.curr_tree_iter][7])
      node_name = self.dialog_input(entry_hint=self.treestore[self.curr_tree_iter][1],
                                    title=_("Insert the New Name for the Node..."),
                                    syntax_highlight=True)
      if node_name == None: return
      self.syntax_highlighting = self.prog_lang_liststore[self.glade.combobox_prog_lang.get_active_iter()][1]
      if self.treestore[self.curr_tree_iter][4] == cons.CUSTOM_COLORS_ID and self.syntax_highlighting != cons.CUSTOM_COLORS_ID:
         if not support.dialog_question(_("Entering the Automatic Syntax Highlighting you will Lose all Custom Colors for This Node, Do you want to Continue?"), self.window):
            self.syntax_highlighting = cons.CUSTOM_COLORS_ID # STEP BACK (we stay in CUSTOM COLORS)
            return
         else:
            # SWITCH TextBuffer -> SourceBuffer
            self.switch_buffer_text_source(self.curr_buffer, self.curr_tree_iter, self.syntax_highlighting)
            self.curr_buffer = self.treestore[self.curr_tree_iter][2]
      elif self.treestore[self.curr_tree_iter][4] != cons.CUSTOM_COLORS_ID and self.syntax_highlighting == cons.CUSTOM_COLORS_ID:
         # SWITCH SourceBuffer -> TextBuffer
         self.switch_buffer_text_source(self.curr_buffer, self.curr_tree_iter, self.syntax_highlighting)
         self.curr_buffer = self.treestore[self.curr_tree_iter][2]
      self.treestore[self.curr_tree_iter][1] = node_name
      self.treestore[self.curr_tree_iter][4] = self.syntax_highlighting
      self.treestore[self.curr_tree_iter][6] = self.glade.tags_searching_entry.get_text()
      self.treestore[self.curr_tree_iter][7] = self.glade.checkbutton_readonly.get_active()
      self.treestore[self.curr_tree_iter][0] = self.get_node_icon(self.treestore[self.curr_tree_iter][5],
                                                                  self.syntax_highlighting)
      if self.syntax_highlighting != cons.CUSTOM_COLORS_ID:
         self.set_sourcebuffer_syntax_highlight(self.curr_buffer, self.syntax_highlighting)
      self.sourceview.set_editable(not self.treestore[self.curr_tree_iter][7])
      self.update_window_save_needed()
      self.sourceview.grab_focus()
      
   def switch_buffer_text_source(self, buffer, iter, new_syntax_highl):
      """Switch TextBuffer -> SourceBuffer or SourceBuffer -> TextBuffer"""
      self.user_active = False
      node_text = buffer.get_text(*buffer.get_bounds())
      self.treestore[iter][2] = self.buffer_create(new_syntax_highl)
      self.treestore[iter][2].set_text(node_text)
      self.sourceview.set_buffer(self.treestore[iter][2])
      self.treestore[iter][2].connect('modified-changed', self.on_modified_changed)
      if new_syntax_highl == cons.CUSTOM_COLORS_ID:
         self.treestore[iter][2].connect('insert-text', self.on_text_insertion)
         self.treestore[iter][2].connect('delete-range', self.on_text_removal)
         self.sourceview.modify_font(pango.FontDescription(self.text_font))
      else:
         self.sourceview.modify_font(pango.FontDescription(self.code_font))
      self.user_active = True
      
   def on_node_changed(self, *args):
      """Actions to be triggered from the changing of node"""
      model, new_iter = self.treeviewselection.get_selected()
      if new_iter == None: return # no node selected
      elif self.curr_tree_iter != None and model[new_iter][3] == model[self.curr_tree_iter][3]:
         return # if i click on an already selected node
      if self.curr_tree_iter != None:
         self.nodes_cursor_pos[model[self.curr_tree_iter][3]] = self.curr_buffer.get_property('cursor-position')
         if self.curr_buffer.get_modified() == True:
            self.file_update = True
            self.curr_buffer.set_modified(False)
            self.state_machine.update_state(self.treestore[self.curr_tree_iter][3])
      self.curr_tree_iter = new_iter
      self.curr_buffer = self.treestore[self.curr_tree_iter][2]
      self.sourceview.set_buffer(self.curr_buffer)
      self.syntax_highlighting = self.treestore[self.curr_tree_iter][4]
      self.curr_buffer.connect('modified-changed', self.on_modified_changed)
      if self.syntax_highlighting == cons.CUSTOM_COLORS_ID:
         self.curr_buffer.connect('insert-text', self.on_text_insertion)
         self.curr_buffer.connect('delete-range', self.on_text_removal)
         self.curr_buffer.connect('mark-set', self.on_textbuffer_mark_set)
         self.sourceview.modify_font(pango.FontDescription(self.text_font))
      else: self.sourceview.modify_font(pango.FontDescription(self.code_font))
      self.sourceview.set_sensitive(True)
      self.sourceview.set_editable(not self.treestore[self.curr_tree_iter][7])
      self.header_node_name_label.set_text("<big><b><i>"+cgi.escape(self.treestore[self.curr_tree_iter][1])+"</i></b></big>")
      self.header_node_name_label.set_use_markup(True)
      self.state_machine.node_selected_changed(self.treestore[self.curr_tree_iter][3])
      self.objects_buffer_refresh()
      # try to restore cursor position if in memory
      if model[new_iter][3] in self.nodes_cursor_pos:
         self.curr_buffer.place_cursor(self.curr_buffer.get_iter_at_offset(self.nodes_cursor_pos[model[new_iter][3]]))
         self.sourceview.scroll_to_mark(self.curr_buffer.get_insert(), 0.3)
   
   def on_textbuffer_mark_set(self, text_buffer, text_iter, text_mark):
      """"""
      if not text_buffer.get_has_selection():
         if self.highlighted_obj: support.set_object_highlight(self, None)
         return
      try:
         iter_sel_start, iter_sel_end = text_buffer.get_selection_bounds()
         if iter_sel_end.get_offset() - iter_sel_start.get_offset() == 1:
            anchor = iter_sel_start.get_child_anchor()
            if anchor != None:
               anchor_dir = dir(anchor)
               if "pixbuf" in anchor_dir: support.set_object_highlight(self, anchor.eventbox)
               elif "liststore" in anchor_dir: support.set_object_highlight(self, anchor.frame)
               elif "sourcebuffer" in anchor_dir: support.set_object_highlight(self, anchor.frame)
      except: pass
   
   def update_window_save_needed(self):
      """Window title preceeded by an asterix"""
      if self.file_name != "": self.window.set_title("*" + self.file_name + " - CherryTree")
      else: self.window.set_title("*CherryTree")
      self.file_update = True
      
   def update_window_save_not_needed(self):
      """Window title not preceeded by an asterix"""
      if self.file_name != "": self.window.set_title(self.file_name + " - CherryTree")
      else: self.window.set_title("CherryTree")
      self.file_update = False
      if self.curr_tree_iter != None:
         self.curr_buffer.set_modified(False)
         curr_iter = self.curr_buffer.get_start_iter()
         while 1:
            anchor = curr_iter.get_child_anchor()
            if anchor != None and "sourcebuffer" in dir(anchor): anchor.sourcebuffer.set_modified(False)
            if not curr_iter.forward_char(): break
      
   def replace_again(self, *args):
      """Continue the previous replace (a_node/in_selected_node/in_all_nodes)"""
      self.find_handler.replace_again()
      
   def find_again(self, *args):
      """Continue the previous search (a_node/in_selected_node/in_all_nodes)"""
      self.find_handler.find_again()
      
   def find_back(self, *args):
      """Continue the previous search (a_node/in_selected_node/in_all_nodes) but in Opposite Direction"""
      self.find_handler.find_back()
      
   def replace_in_selected_node(self, *args):
      """Replace a pattern in the selected Node"""
      self.find_handler.replace_in_selected_node()
      
   def find_in_selected_node(self, *args):
      """Search for a pattern in the selected Node"""
      if self.curr_tree_iter == None:
         support.dialog_warning(_("No Node is Selected!"), self.window)
         return
      self.find_handler.find_in_selected_node()
      
   def replace_in_all_nodes(self, *args):
      """Replace the pattern in all the Tree Nodes"""
      self.find_handler.replace_in_all_nodes()
      
   def find_in_all_nodes(self, *args):
      """Search for a pattern in all the Tree Nodes"""
      if self.tree_is_empty():
         support.dialog_warning(_("The Tree is Empty!"), self.window)
         return
      self.find_handler.find_in_all_nodes()
      
   def replace_in_nodes_names(self, *args):
      """Replace the pattern between all the Node's Names"""
      self.find_handler.replace_in_nodes_names()
      
   def find_a_node(self, *args):
      """Search for a pattern between all the Node's Names"""
      if self.tree_is_empty():
         support.dialog_warning(_("The Tree is Empty!"), self.window)
         return
      self.find_handler.find_a_node()
      
   def get_tree_iter_last_sibling(self, node_iter):
      """Returns the last top level iter or None if the tree is empty"""
      if node_iter == None:
         node_iter = self.treestore.get_iter_first()
         if node_iter == None: return None
      next_iter = self.treestore.iter_next(node_iter)
      while next_iter != None:
         node_iter = next_iter
         next_iter = self.treestore.iter_next(next_iter)
      return node_iter
      
   def get_tree_iter_prev_sibling(self, model, node_iter):
      """Returns the previous sibling iter or None if the given iter is the first"""
      node_path = model.get_path(node_iter)
      sibling_index = len(node_path)-1
      prev_iter = None
      while prev_iter == None and node_path[sibling_index] > 0:
         node_path_list = list(node_path)
         node_path_list[sibling_index] -= 1
         prev_path = tuple(node_path_list)
         prev_iter = model.get_iter(prev_path)
      return prev_iter
      
   def go_back(self, *args):
      """Go to the Previous Visited Node"""
      self.go_bk_fw_click = True
      new_node_id = self.state_machine.requested_previous_visited()
      if new_node_id:
         node_iter = self.get_tree_iter_from_node_id(new_node_id)
         if node_iter: self.treeview_safe_set_cursor(node_iter)
         else: self.go_back()
      self.go_bk_fw_click = False
      
   def go_forward(self, *args):
      """Go to the Next Visited Node"""
      self.go_bk_fw_click = True
      new_node_id = self.state_machine.requested_next_visited()
      if new_node_id:
         node_iter = self.get_tree_iter_from_node_id(new_node_id)
         if node_iter: self.treeview_safe_set_cursor(node_iter)
         else: self.go_forward()
      self.go_bk_fw_click = False
      
   def requested_step_back(self, *args):
      """Step Back for the Current Node, if Possible"""
      if self.curr_tree_iter == None: return
      if self.syntax_highlighting == cons.CUSTOM_COLORS_ID:
         # TEXT BUFFER STATE MACHINE
         step_back = self.state_machine.requested_previous_state(self.treestore[self.curr_tree_iter][3])
         # step_back is [ [rich_text, pixbuf_table_vector, cursor_position],... ]
         if step_back != None:
            self.user_active = False
            self.xml_handler.dom_to_buffer(self.curr_buffer, step_back[0])
            pixbuf_table_vector = step_back[1]
            # pixbuf_table_vector is [ [ "pixbuf"/"table"/"codebox", [offset, pixbuf, alignment] ],... ]
            for element in pixbuf_table_vector:
               if element[0] == "pixbuf": self.state_machine.load_embedded_image_element(self.curr_buffer, element[1])
               elif element[0] == "table": self.state_machine.load_embedded_table_element(self.curr_buffer, element[1])
               elif element[0] == "codebox": self.state_machine.load_embedded_codebox_element(self.curr_buffer, element[1])
            self.sourceview.set_buffer(None)
            self.sourceview.set_buffer(self.curr_buffer)
            self.objects_buffer_refresh()
            self.curr_buffer.place_cursor(self.curr_buffer.get_iter_at_offset(step_back[2]))
            self.sourceview.scroll_to_mark(self.curr_buffer.get_insert(), 0.3)
            self.user_active = True
            self.update_window_save_needed()
      elif self.curr_buffer.can_undo():
         self.curr_buffer.undo()
         self.update_window_save_needed()
      
   def requested_step_ahead(self, *args):
      """Step Ahead for the Current Node, if Possible"""
      if self.curr_tree_iter == None: return
      if self.syntax_highlighting == cons.CUSTOM_COLORS_ID:
         # TEXT BUFFER STATE MACHINE
         step_ahead = self.state_machine.requested_subsequent_state(self.treestore[self.curr_tree_iter][3])
         # step_ahead is [ [rich_text, pixbuf_table_vector, cursor_position],... ]
         if step_ahead != None:
            self.user_active = False
            self.xml_handler.dom_to_buffer(self.curr_buffer, step_ahead[0])
            pixbuf_table_vector = step_ahead[1]
            # pixbuf_table_vector is [ [ "pixbuf"/"table", [offset, pixbuf, alignment] ],... ]
            for element in pixbuf_table_vector:
               if element[0] == "pixbuf": self.state_machine.load_embedded_image_element(self.curr_buffer, element[1])
               elif element[0] == "table": self.state_machine.load_embedded_table_element(self.curr_buffer, element[1])
               elif element[0] == "codebox": self.state_machine.load_embedded_codebox_element(self.curr_buffer, element[1])
            self.sourceview.set_buffer(None)
            self.sourceview.set_buffer(self.curr_buffer)
            self.objects_buffer_refresh()
            self.curr_buffer.place_cursor(self.curr_buffer.get_iter_at_offset(step_ahead[2]))
            self.sourceview.scroll_to_mark(self.curr_buffer.get_insert(), 0.3)
            self.user_active = True
            self.update_window_save_needed()
      elif self.curr_buffer.can_redo():
         self.curr_buffer.redo()
         self.update_window_save_needed()
   
   def objects_buffer_refresh(self):
      """Buffer Refresh (Needed for Objects)"""
      refresh = self.state_machine.requested_current_state(self.treestore[self.curr_tree_iter][3])
      # refresh is [ [rich_text, pixbuf_table_vector, cursor_position],... ]
      pixbuf_table_vector = refresh[1]
      if len(pixbuf_table_vector) > 0:
         self.user_active = False
         self.curr_buffer.set_text("")
         self.xml_handler.dom_to_buffer(self.curr_buffer, refresh[0])
         for element in pixbuf_table_vector:
            if element[0] == "pixbuf": self.state_machine.load_embedded_image_element(self.curr_buffer, element[1])
            elif element[0] == "table": self.state_machine.load_embedded_table_element(self.curr_buffer, element[1])
            elif element[0] == "codebox": self.state_machine.load_embedded_codebox_element(self.curr_buffer, element[1])
         self.curr_buffer.set_modified(False)
         self.user_active = True
   
   def on_text_insertion(self, sourcebuffer, text_iter, text_inserted, length):
      """Text insertion callback"""
      if self.user_active:
         self.state_machine.text_variation(self.treestore[self.curr_tree_iter][3], text_inserted)
   
   def on_text_removal(self, sourcebuffer, start_iter, end_iter):
      """Text removal callback"""
      if self.user_active:
         self.state_machine.text_variation(self.treestore[self.curr_tree_iter][3], 
                                           sourcebuffer.get_text(start_iter, end_iter))
   
   def horizontal_rule_insert(self, action):
      """Insert a Horizontal Line"""
      if self.curr_tree_iter == None:
         support.dialog_warning(_("No Node is Selected"), self.window)
         return
      self.curr_buffer.insert_at_cursor(cons.HORIZONTAL_RULE)
   
   def dialog_input(self, entry_hint=None, title=None, search_opt=False, replace_opt=False, syntax_highlight=False):
      """Opens the Input Dialog"""
      if title != None: self.glade.inputdialog.set_title(title)
      if entry_hint != None: self.glade.input_entry.set_text(entry_hint)
      else: self.glade.input_entry.set_text("")
      self.glade.input_entry.grab_focus()
      self.glade.search_options_frame.set_property("visible", search_opt)
      self.glade.replace_options_frame.set_property("visible", replace_opt)
      self.glade.syntax_highlighting_frame.set_property("visible", syntax_highlight)
      self.glade.tags_searching_frame.set_property("visible", syntax_highlight)
      self.glade.checkbutton_readonly.set_property("visible", syntax_highlight)
      response = self.glade.inputdialog.run()
      self.glade.inputdialog.hide()
      if response == 1:
         input_text = self.glade.input_entry.get_text().decode("utf-8")
         if len(input_text) > 0: return input_text
         else: return None
      else: return None
      
   def toolbar_icons_size_increase(self, *args):
      """Increase the Size of the Toolbar Icons"""
      if self.toolbar_icon_size == 5:
         support.dialog_info(_("The Size of the Toolbar Icons is already at the Maximum Value"), self.window)
         return
      self.toolbar_icon_size += 1
      self.ui.get_widget("/ToolBar").set_property("icon-size", config.ICONS_SIZE[self.toolbar_icon_size])
   
   def toolbar_icons_size_decrease(self, *args):
      """Decrease the Size of the Toolbar Icons"""
      if self.toolbar_icon_size == 1:
         support.dialog_info(_("The Size of the Toolbar Icons is already at the Minimum Value"), self.window)
         return
      self.toolbar_icon_size -= 1
      self.ui.get_widget("/ToolBar").set_property("icon-size", config.ICONS_SIZE[self.toolbar_icon_size])
      
   def toggle_show_hide_toolbar(self, *args):
      """Toggle Show/Hide the Toolbar"""
      if self.ui.get_widget("/ToolBar").get_property("visible"): self.ui.get_widget("/ToolBar").hide()
      else: self.ui.get_widget("/ToolBar").show()
      
   def toggle_show_hide_tree(self, *args):
      """Toggle Show/Hide the Tree"""
      if self.scrolledwindow_tree.get_property("visible"):
         self.scrolledwindow_tree.hide()
      else: self.scrolledwindow_tree.show()
      
   def toggle_show_hide_node_name_header(self, *args):
      """Toggle Show/Hide the Node Title Header"""
      if self.header_node_name_label.get_property("visible"):
         self.header_node_name_label.hide()
      else: self.header_node_name_label.show()
      
   def quit_application(self, *args):
      """Just Hide or Quit the gtk main loop"""
      if self.systray: self.window.hide()
      else: self.quit_application_totally()
      
   def quit_application_totally(self, *args):
      """The process is Shut Down"""
      if not self.check_unsaved():
         self.really_quit = False # user pressed cancel
         return
      config.config_file_save(self)
      self.window.destroy()
      if "status_icon" in dir(self): self.status_icon.set_visible(False)
      
   def on_window_delete_event(self, widget, event, data=None):
      """Before close the application (from the window top right X)..."""
      self.really_quit = True
      self.quit_application()
      if not self.really_quit: return True # stop the delete event (user pressed cancel)
      else: return self.systray # True == stop the delete event, False == propogate the delete event
      
   def check_unsaved(self):
      """Before close the current document, check for possible Unsaved"""
      if self.curr_tree_iter != None and (self.curr_buffer.get_modified() == True or self.file_update == True):
         if self.autosave_on_quit: response = 2
         else:
            response = self.glade.exitdialog.run()
            self.glade.exitdialog.hide()
         if response == 2: self.file_save() # button YES pressed or autosave ON
      else: response = 0 # no need to save
      if response == 6: return False # button CANCEL
      else: return True
      
   def dialog_about(self, *args):
      """Show the About Dialog and hide it when a button is pressed"""
      self.glade.aboutdialog.run()
      self.glade.aboutdialog.hide()
      
   def anchor_handle(self, action):
      """Insert an Anchor"""
      if not self.node_sel_and_rich_text(): return
      iter_insert = self.curr_buffer.get_iter_at_mark(self.curr_buffer.get_insert())
      self.anchor_edit_dialog(gtk.gdk.pixbuf_new_from_file(cons.ANCHOR_CHAR), iter_insert)
      
   def anchor_edit(self, *args):
      """Edit an Anchor"""
      iter_insert = self.curr_buffer.get_iter_at_child_anchor(self.curr_anchor_anchor)
      iter_bound = iter_insert.copy()
      iter_bound.forward_char()
      self.anchor_edit_dialog(self.curr_anchor_anchor.pixbuf, iter_insert, iter_bound)
      
   def anchor_edit_dialog(self, pixbuf, iter_insert, iter_bound=None):
      """Anchor Edit Dialog"""
      if "anchor" in dir (pixbuf):
         self.glade.anchor_insert_edit_entry.set_text(pixbuf.anchor)
         self.glade.anchorhandledialog.set_title(_("Edit Anchor"))
      else:
         self.glade.anchor_insert_edit_entry.set_text("")
         self.glade.anchorhandledialog.set_title(_("Insert Anchor"))
      self.glade.anchor_insert_edit_entry.grab_focus()
      self.glade.anchor_enter_name_hbox.show()
      self.glade.scrolledwindow_anchors_list.hide()
      response = self.glade.anchorhandledialog.run()
      self.glade.anchorhandledialog.hide()
      if response != 1: return # the user aborted the operation
      anchor = self.glade.anchor_insert_edit_entry.get_text().strip()
      if anchor == "":
         support.dialog_error(_("The Anchor Name is Mandatory!"), self.window)
         return
      pixbuf.anchor = anchor
      if iter_bound != None: # only in case of modify
         image_justification = self.state_machine.get_iter_alignment(iter_insert)
         image_offset = iter_insert.get_offset()
         self.curr_buffer.delete(iter_insert, iter_bound)
         iter_insert = self.curr_buffer.get_iter_at_offset(image_offset)
      else: image_justification = None
      self.image_insert(iter_insert, pixbuf, image_justification)
      
   def toc_insert(self, *args):
      """Insert Table Of Contents"""
      if not self.node_sel_and_rich_text(): return
      if not self.xml_handler.toc_insert(self.curr_buffer, self.treestore[self.curr_tree_iter][3]):
         support.dialog_warning(_("Not Any H1 or H2 Formatting Found"), self.window)
   
   def table_handle(self, *args):
      """Insert Table"""
      if not self.node_sel_and_rich_text(): return
      self.tables_handler.table_handle()
   
   def codebox_handle(self, *args):
      """Insert Code Box"""
      if not self.node_sel_and_rich_text(): return
      self.codeboxes_handler.codebox_handle()
      
   def on_radiobutton_codebox_pixels_toggled(self, radiobutton):
      """Radiobutton CodeBox Pixels/Percent Toggled"""
      if not self.user_active: return
      if radiobutton.get_active():
         self.glade.spinbutton_codebox_width.set_value(700)
      else: self.glade.spinbutton_codebox_width.set_value(100)
      
   def node_sel_and_rich_text(self):
      """Returns True if there's not a node selected or is not rich text"""
      if self.curr_tree_iter == None:
         support.dialog_warning(_("No Node is Selected"), self.window)
         return False
      if self.syntax_highlighting != cons.CUSTOM_COLORS_ID:
         support.dialog_warning(_("Automatic Syntax Highlighting Must be Disabled in order to Use This Feature"), self.window)
         return False
      return True
      
   def tree_cell_edited(self, cell, path, new_text):
      """A Table Cell is going to be Edited"""
      if new_text != self.treestore[path][1]:
         self.treestore[path][1] = new_text
         self.header_node_name_label.set_text("<big><b><i>"+new_text+"</i></b></big>")
         self.header_node_name_label.set_use_markup(True)
         self.update_window_save_needed()
      
   def tree_info(self, action):
      """Tree Summary Information"""
      if self.tree_is_empty():
         support.dialog_warning(_("The Tree is Empty!"), self.window)
         return
      dialog = gtk.Dialog(title=_("Tree Summary Information"),
                          parent=self.window,
                          flags=gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
                          buttons=(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT) )
      dialog.set_default_size(400, 300)
      dialog.set_transient_for(self.window)
      dialog.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
      table = gtk.Table(5, 2)
      label = gtk.Label()
      label.set_markup("<b>" + _("Number of Text Nodes") + "</b>")
      table.attach(label, 0, 1, 0, 1)
      label = gtk.Label()
      label.set_markup("<b>" + _("Number of Code Nodes") + "</b>")
      table.attach(label, 0, 1, 1, 2)
      label = gtk.Label()
      label.set_markup("<b>" + _("Number of Images") + "</b>")
      table.attach(label, 0, 1, 2, 3)
      label = gtk.Label()
      label.set_markup("<b>" + _("Number of Tables") + "</b>")
      table.attach(label, 0, 1, 3, 4)
      label = gtk.Label()
      label.set_markup("<b>" + _("Number of CodeBoxes") + "</b>")
      table.attach(label, 0, 1, 4, 5)
      self.summary_nodes_text_num = 0
      self.summary_nodes_code_num = 0
      self.summary_images_num = 0
      self.summary_tables_num = 0
      self.summary_codeboxes_num = 0
      # full tree parsing
      tree_iter = self.treestore.get_iter_first()
      while tree_iter != None:
         self.tree_info_iter(tree_iter)
         tree_iter = self.treestore.iter_next(tree_iter)
      label = gtk.Label("%s" % self.summary_nodes_text_num)
      table.attach(label, 1, 2, 0, 1)
      label = gtk.Label("%s" % self.summary_nodes_code_num)
      table.attach(label, 1, 2, 1, 2)
      label = gtk.Label("%s" % self.summary_images_num)
      table.attach(label, 1, 2, 2, 3)
      label = gtk.Label("%s" % self.summary_tables_num)
      table.attach(label, 1, 2, 3, 4)
      label = gtk.Label("%s" % self.summary_codeboxes_num)
      table.attach(label, 1, 2, 4, 5)
      content_area = dialog.get_content_area()
      content_area.pack_start(table)
      content_area.show_all()
      dialog.get_action_area().set_layout(gtk.BUTTONBOX_SPREAD)
      dialog.run()
      dialog.destroy()
      
   def tree_info_iter(self, tree_iter):
      """Tree Summary Information Iteration"""
      curr_buffer = self.treestore[tree_iter][2]
      pixbuf_table_vector = self.state_machine.get_embedded_pixbufs_tables_codeboxes(curr_buffer)
      # pixbuf_table_vector is [ [ "pixbuf"/"table", [offset, pixbuf, alignment] ],... ]
      if self.treestore[tree_iter][4] == cons.CUSTOM_COLORS_ID: self.summary_nodes_text_num += 1
      else: self.summary_nodes_code_num += 1
      curr_node_images = 0
      curr_node_tables = 0
      curr_node_codeboxes = 0
      for element in pixbuf_table_vector:
         if element[0] == "pixbuf": curr_node_images += 1
         elif element[0] == "table": curr_node_tables += 1
         elif element[0] == "codebox": curr_node_codeboxes += 1
      self.summary_images_num += curr_node_images
      self.summary_tables_num += curr_node_tables
      self.summary_codeboxes_num += curr_node_codeboxes
      # iterate children
      tree_iter = self.treestore.iter_children(tree_iter)
      while tree_iter != None:
         self.tree_info_iter(tree_iter)
         tree_iter = self.treestore.iter_next(tree_iter)
      
   def image_handle(self, *args):
      """Insert/Edit Image"""
      if not self.node_sel_and_rich_text(): return
      iter_insert = self.curr_buffer.get_iter_at_mark(self.curr_buffer.get_insert())
      filename = support.dialog_file_select(curr_folder=self.pick_dir, parent=self.window)
      if filename == None: return
      self.pick_dir = os.path.dirname(filename)
      pixbuf = gtk.gdk.pixbuf_new_from_file(filename)
      self.image_edit_dialog(pixbuf, self.curr_buffer.get_iter_at_mark(self.curr_buffer.get_insert()))
      
   def image_edit_dialog(self, pixbuf, insert_iter, iter_bound=None):
      """Insert/Edit Image Dialog"""
      self.original_pixbuf = pixbuf
      self.temp_image_width = pixbuf.get_width()
      self.temp_image_height = pixbuf.get_height()
      self.image_w_h_ration = float(self.temp_image_width)/self.temp_image_height
      self.image_load_into_dialog()
      response = self.glade.imageeditdialog.run()
      self.glade.imageeditdialog.hide()
      if response != 1: return # cancel was pressed
      if iter_bound != None: # only in case of modify
         image_justification = self.state_machine.get_iter_alignment(insert_iter)
         image_offset = insert_iter.get_offset()
         self.curr_buffer.delete(insert_iter, iter_bound)
         insert_iter = self.curr_buffer.get_iter_at_offset(image_offset)
      else: image_justification = None
      self.image_insert(insert_iter,
                        self.original_pixbuf.scale_simple(int(self.temp_image_width),
                                                          int(self.temp_image_height),
                                                          gtk.gdk.INTERP_BILINEAR),
                        image_justification)
      
   def image_insert(self, iter_insert, pixbuf, image_justification=None):
      image_offset = iter_insert.get_offset()
      anchor = self.curr_buffer.create_child_anchor(iter_insert)
      anchor.pixbuf = pixbuf
      anchor.eventbox = gtk.EventBox()
      anchor.eventbox.set_visible_window(False)
      if "anchor" in dir(pixbuf):
         anchor.eventbox.connect("button-press-event", self.on_mouse_button_clicked_anchor, anchor)
         anchor.eventbox.set_tooltip_text(pixbuf.anchor)
      else:
         anchor.eventbox.connect("button-press-event", self.on_mouse_button_clicked_image, anchor)
      anchor.image = gtk.Image()
      anchor.eventbox.add(anchor.image)
      anchor.image.set_from_pixbuf(anchor.pixbuf)
      self.sourceview.add_child_at_anchor(anchor.eventbox, anchor)
      anchor.eventbox.show_all()
      if image_justification:
         self.state_machine.apply_image_justification(self.curr_buffer.get_iter_at_offset(image_offset),
                                                      image_justification)
      else:
         # if I apply a justification, the state is already updated
         self.state_machine.update_state(self.treestore[self.curr_tree_iter][3])
      
   def image_edit(self, *args):
      """Edit the selected Image"""
      iter_insert = self.curr_buffer.get_iter_at_child_anchor(self.curr_image_anchor)
      iter_bound = iter_insert.copy()
      iter_bound.forward_char()
      self.image_edit_dialog(self.curr_image_anchor.pixbuf, iter_insert, iter_bound)
      
   def image_save(self, *args):
      """Save to Disk the selected Image"""
      filename = support.dialog_file_save_as(curr_folder=self.pick_dir,
                                             filter_pattern="*.png",
                                             filter_name=_("PNG Image"),
                                             parent=self.window)
      if filename == None: return
      if len(filename) < 4 or filename[-4:] != ".png": filename += ".png"
      self.pick_dir = os.path.dirname(filename)
      try: self.curr_image_anchor.pixbuf.save(filename, "png")
      except: support.dialog_error(_("Write to %s Failed") % filename, self.window)
      
   def object_set_selection(self, anchor):
      """Put Selection Upon the Image"""
      iter_image = self.curr_buffer.get_iter_at_child_anchor(anchor)
      iter_bound = iter_image.copy()
      iter_bound.forward_char()
      self.curr_buffer.select_range(iter_image, iter_bound)
      
   def paste_as_plain_text(self, *args):
      """Paste as Plain Text"""
      self.clipboard_handler.force_plain_text = True
      self.sourceview.emit("paste-clipboard")
      
   def image_cut(self, *args):
      """Cut Image"""
      self.object_set_selection(self.curr_image_anchor)
      self.sourceview.emit("cut-clipboard")
   
   def image_copy(self, *args):
      """Copy Image"""
      self.object_set_selection(self.curr_image_anchor)
      self.sourceview.emit("copy-clipboard")
   
   def image_delete(self, *args):
      """Delete Image"""
      self.object_set_selection(self.curr_image_anchor)
      self.curr_buffer.delete_selection(True, self.sourceview.get_editable())
      self.sourceview.grab_focus()
      
   def on_mouse_button_clicked_image(self, widget, event, anchor):
      """Catches mouse buttons clicks upon images"""
      self.curr_image_anchor = anchor
      self.object_set_selection(self.curr_image_anchor)
      if event.button == 3:
         self.ui.get_widget("/ImageMenu").popup(None, None, None, event.button, event.time)
      elif event.type == gtk.gdk._2BUTTON_PRESS: self.image_edit()
      return True # do not propagate the event
   
   def on_mouse_button_clicked_anchor(self, widget, event, anchor):
      """Catches mouse buttons clicks upon images"""
      self.curr_anchor_anchor = anchor
      self.object_set_selection(self.curr_anchor_anchor)
      if event.button == 3:
         self.ui.get_widget("/AnchorMenu").popup(None, None, None, event.button, event.time)
      elif event.type == gtk.gdk._2BUTTON_PRESS: self.anchor_edit()
      return True # do not propagate the event
      
   def image_load_into_dialog(self):
      """Load/Reload the Image Under Editing"""
      self.user_active = False
      self.glade.spinbutton_image_width.set_value(self.temp_image_width)
      self.glade.spinbutton_image_height.set_value(self.temp_image_height)
      if self.temp_image_width <= 900 and self.temp_image_height <= 600:
         # original size into the dialog
         pixbuf = self.original_pixbuf.scale_simple(int(self.temp_image_width),
                                                    int(self.temp_image_height),
                                                    gtk.gdk.INTERP_BILINEAR)
      else:
         # reduced size visible into the dialog
         if self.temp_image_width > 900:
            temp_image_width = 900
            temp_image_height = temp_image_width / self.image_w_h_ration
         else:
            temp_image_height = 600
            temp_image_width = temp_image_height * self.image_w_h_ration
         pixbuf = self.original_pixbuf.scale_simple(int(temp_image_width),
                                                    int(temp_image_height),
                                                    gtk.gdk.INTERP_BILINEAR)
      self.glade.image_under_editing.set_from_pixbuf(pixbuf)
      self.user_active = True
      
   def on_button_rotate_90_cw_clicked(self, *args):
      """Image Edit - Rotate 90 ClockWise"""
      self.original_pixbuf = self.original_pixbuf.rotate_simple(270)
      self.image_w_h_ration = 1/self.image_w_h_ration
      new_width = self.temp_image_height # new width is the former height and vice versa
      self.temp_image_height = self.temp_image_width
      self.temp_image_width = new_width
      self.image_load_into_dialog()
   
   def on_button_rotate_90_ccw_clicked(self, *args):
      """Image Edit - Rotate 90 CounterClockWise"""
      self.original_pixbuf = self.original_pixbuf.rotate_simple(90)
      self.image_w_h_ration = 1/self.image_w_h_ration
      new_width = self.temp_image_height # new width is the former height and vice versa
      self.temp_image_height = self.temp_image_width
      self.temp_image_width = new_width
      self.image_load_into_dialog()
   
   def on_spinbutton_image_width_value_changed(self, spinbutton):
      """Image Edit - Width Change Handling"""
      if self.user_active:
         self.temp_image_width = self.glade.spinbutton_image_width.get_value()
         self.temp_image_height = self.temp_image_width / self.image_w_h_ration
         self.image_load_into_dialog()
   
   def on_spinbutton_image_height_value_changed(self, spinbutton):
      """Image Edit - Height Change Handling"""
      if self.user_active:
         self.temp_image_height = self.glade.spinbutton_image_height.get_value()
         self.temp_image_width = self.temp_image_height * self.image_w_h_ration
         self.image_load_into_dialog()
      
   def apply_tag_foreground(self, *args):
      """The Foreground Color Chooser Button was Pressed"""
      self.apply_tag("foreground")
      
   def apply_tag_background(self, *args):
      """The Background Color Chooser Button was Pressed"""
      self.apply_tag("background")
      
   def apply_tag_link(self, *args):
      """The Link Insert Button was Pressed"""
      self.apply_tag("link")
      
   def apply_tag_bold(self, *args):
      """The Bold Button was Pressed"""
      self.apply_tag("weight", "heavy")
      
   def apply_tag_italic(self, *args):
      """The Italic Button was Pressed"""
      self.apply_tag("style", "italic")
      
   def apply_tag_underline(self, *args):
      """The Underline Button was Pressed"""
      self.apply_tag("underline", "single")
      
   def apply_tag_strikethrough(self, *args):
      """The Strikethrough Button was Pressed"""
      self.apply_tag("strikethrough", "true")
      
   def apply_tag_small(self, *args):
      """The Small Button was Pressed"""
      self.apply_tag("scale", "small")
   
   def apply_tag_h1(self, *args):
      """The H1 Button was Pressed"""
      self.apply_tag("scale", "h1")
      
   def apply_tag_h2(self, *args):
      """The H2 Button was Pressed"""
      self.apply_tag("scale", "h2")
      
   def apply_tag_justify_right(self, *args):
      """The Justify Right Button was Pressed"""
      iter_start, iter_end = self.lists_handler.get_paragraph_iters()
      self.apply_tag("justification", "right", iter_sel_start=iter_start, iter_sel_end=iter_end)
   
   def apply_tag_justify_left(self, *args):
      """The Justify Left Button was Pressed"""
      iter_start, iter_end = self.lists_handler.get_paragraph_iters()
      self.apply_tag("justification", "left", iter_sel_start=iter_start, iter_sel_end=iter_end)
   
   def apply_tag_justify_center(self, *args):
      """The Justify Center Button was Pressed"""
      iter_start, iter_end = self.lists_handler.get_paragraph_iters()
      self.apply_tag("justification", "center", iter_sel_start=iter_start, iter_sel_end=iter_end)
      
   def apply_tag_try_automatic_bounds(self):
      """Try to Select a Word Forward/Backward the Cursor"""
      iter_start = self.curr_buffer.get_iter_at_mark(self.curr_buffer.get_insert())
      iter_end = iter_start.copy()
      end_moved = False
      while iter_end != None:
         char = iter_end.get_char()
         match = re.match('\w', char) # alphanumeric char
         if not match: break # we got it
         elif not iter_end.forward_char(): break # we reached the buffer end
         end_moved = True
      if not end_moved: iter_start.backward_char() # we could be at the end of a word
      while iter_start != None:
         char = iter_start.get_char()
         match = re.match('\w', char) # alphanumeric char
         if not match: # we got it
            iter_start.forward_char() # step forward to the beginning of the word
            break
         elif not iter_start.backward_char(): break # we reached the buffer start
      if iter_start.equal(iter_end): return False
      else:
         self.curr_buffer.move_mark(self.curr_buffer.get_insert(), iter_end)
         self.curr_buffer.move_mark(self.curr_buffer.get_selection_bound(), iter_start)
         return True
      
   def list_bulleted_handler(self, *args):
      """Handler of the Bulleted List"""
      if self.syntax_highlighting != cons.CUSTOM_COLORS_ID:
         support.dialog_warning(_("Automatic Syntax Highlighting Must be Disabled in order to Use This Feature"), self.window)
         return
      self.lists_handler.list_bulleted_handler()
      
   def list_numbered_handler(self, *args):
      """Handler of the Numbered List"""
      if self.syntax_highlighting != cons.CUSTOM_COLORS_ID:
         support.dialog_warning(_("Automatic Syntax Highlighting Must be Disabled in order to Use This Feature"), self.window)
         return
      self.lists_handler.list_numbered_handler()
      
   def list_todo_handler(self, *args):
      """Handler of the ToDo List"""
      if self.syntax_highlighting != cons.CUSTOM_COLORS_ID:
         support.dialog_warning(_("Automatic Syntax Highlighting Must be Disabled in order to Use This Feature"), self.window)
         return
      self.lists_handler.list_todo_handler()
      
   def apply_tag_latest(self, *args):
      """The Iterate Tagging Button was Pressed"""
      if self.latest_tag[0] == "": support.dialog_warning(_("No Previous Text Format Was Performed During This Session"), self.window)
      else: self.apply_tag(*self.latest_tag)
      
   def apply_tag(self, tag_property, property_value=None, iter_sel_start=None, iter_sel_end=None):
      """Apply a tag"""
      if self.syntax_highlighting != cons.CUSTOM_COLORS_ID and self.user_active:
         support.dialog_warning(_("Automatic Syntax Highlighting Must be Disabled in order to Use This Feature"), self.window)
         return
      if iter_sel_start == None and iter_sel_end == None:
         if tag_property != "justification":
            if self.curr_tree_iter == None:
               support.dialog_warning(_("No Node is Selected"), self.window)
               return
            if tag_property == "link": link_node_id = None
            if not self.curr_buffer.get_has_selection():
               if tag_property != "link":
                  if not self.apply_tag_try_automatic_bounds():
                     support.dialog_warning(_("No Text is Selected"), self.window)
                     return
               else:
                  tag_property_value = self.link_check_around_cursor()
                  if tag_property_value == "":
                     if not self.apply_tag_try_automatic_bounds():
                        support.dialog_warning(_("No Text is Selected"), self.window)
                        return
                  else:
                     vector = tag_property_value.split()
                     self.link_type = vector[0]
                     if self.link_type == "webs": self.glade.link_website_entry.set_text(vector[1])
                     elif self.link_type in ["file", "fold"]:
                        self.glade.entry_file_to_link_to.set_text(base64.b64decode(vector[1]))
                     elif self.link_type == "node":
                        link_node_id = long(vector[1])
                        if len(vector) >= 3:
                           if len(vector) == 3: anchor_name = vector[2]
                           else: anchor_name = tag_property_value[len(vector[0]) + len(vector[1]) + 2:]
                           self.glade.link_anchor_entry.set_text(anchor_name)
                     else:
                        support.dialog_error("Tag Name Not Recognized! (%s)" % self.link_type, self.window)
                        self.link_type = "webs"
                        return
                     self.glade.radiobutton_link_website.set_active(self.link_type == "webs")
                     self.glade.radiobutton_link_node_anchor.set_active(self.link_type == "node")
                     self.glade.radiobutton_link_file.set_active(self.link_type == "file")
                     self.glade.radiobutton_link_folder.set_active(self.link_type == "fold")
            iter_sel_start, iter_sel_end = self.curr_buffer.get_selection_bounds()
         else:
            support.dialog_warning(_("The Cursor is Not into a Paragraph"), self.window)
            return
      if property_value == None:
         if tag_property == "link":
            if self.next_chars_from_iter_are(iter_sel_start, 7, "http://")\
            or self.next_chars_from_iter_are(iter_sel_start, 8, "https://"):
               self.link_type = "webs"
               self.glade.link_website_entry.set_text(self.curr_buffer.get_text(iter_sel_start, iter_sel_end))
            self.node_choose_view_exist_or_create(link_node_id)
            self.glade.choosenodedialog.set_title(_("Insert/Edit a Link"))
            self.glade.link_dialog_top_vbox.show()
            self.glade.frame_link_anchor.show()
            self.link_type_changed_on_dialog()
            response = self.glade.choosenodedialog.run()
            self.glade.choosenodedialog.hide()
            if response != 1: return # the user aborted the operation
            if self.link_type == "webs":
               link_url = self.glade.link_website_entry.get_text().strip()
               if not link_url: return
               if len(link_url) < 8\
               or (link_url[0:7] != "http://" and link_url[0:8] != "https://"):
                  link_url = "http://" + link_url
               property_value = "webs" + cons.CHAR_SPACE + link_url
            elif self.link_type in ["file", "fold"]:
               link_uri = self.glade.entry_file_to_link_to.get_text().strip()
               if not link_uri: return
               link_uri = base64.b64encode(link_uri)
               property_value = self.link_type + cons.CHAR_SPACE + link_uri
            elif self.link_type == "node":
               model, tree_iter = self.treeviewselection_2.get_selected()
               link_anchor = self.glade.link_anchor_entry.get_text().strip()
               property_value = "node" + cons.CHAR_SPACE + str(self.treestore[tree_iter][3])
               if len(link_anchor) > 0: property_value += cons.CHAR_SPACE + link_anchor
         else:
            if tag_property[0] == 'f':
               if self.curr_colors['f']: self.glade.colorselection.set_current_color(self.curr_colors['f'])
            elif tag_property[0] == 'b':
               if self.curr_colors['b']: self.glade.colorselection.set_current_color(self.curr_colors['b'])
            else: print "ERROR bad tag_property"
            response = self.glade.colorselectiondialog.run()
            self.glade.colorselectiondialog.hide()
            if response == 2: return # cancel was clicked
            self.curr_colors[tag_property[0]] = self.glade.colorselection.get_current_color()
            property_value = self.curr_colors[tag_property[0]].to_string()
      if tag_property != "link":
         self.latest_tag = [tag_property, property_value]
      curr_tags = iter_sel_start.get_tags()
      # if there's already a tag about this property, we remove it before apply the new one
      for curr_tag in curr_tags:
         tag_name = curr_tag.get_property("name")
         if (tag_property == "weight" and tag_name[0:7] == "weight_")\
         or (tag_property == "style" and tag_name[0:6] == "style_")\
         or (tag_property == "underline" and tag_name[0:10] == "underline_")\
         or (tag_property == "strikethrough" and tag_name[0:14] == "strikethrough_"):
            self.curr_buffer.remove_tag(curr_tag, iter_sel_start, iter_sel_end)
            return # just tag removal
         elif tag_property == "scale" and tag_name[0:6] == "scale_":
            self.curr_buffer.remove_tag(curr_tag, iter_sel_start, iter_sel_end)
            #print property_value, tag_name[6:]
            if property_value == tag_name[6:]: return # just tag removal
         elif tag_property == "justification" and tag_name[0:14] == "justification_":
            self.curr_buffer.remove_tag(curr_tag, iter_sel_start, iter_sel_end)
         elif (tag_property == "foreground" and tag_name[0:11] == "foreground_")\
         or (tag_property == "background" and tag_name[0:11] == "background_")\
         or (tag_property == "link" and tag_name[0:5] == "link_"):
            self.curr_buffer.remove_tag(curr_tag, iter_sel_start, iter_sel_end)
      self.curr_buffer.apply_tag_by_name(self.apply_tag_exist_or_create(tag_property, property_value),
                                         iter_sel_start, iter_sel_end)
      if self.user_active:
         if self.file_update == False: self.update_window_save_needed() # file save needed
         self.state_machine.update_state(self.treestore[self.curr_tree_iter][3])
      
   def next_chars_from_iter_are(self, iter_start, num, chars):
      """Returns True if the Given Chars are the next 'num' after iter"""
      iter = iter_start.copy()
      for i in range(num):
         if iter.get_char() != chars[i]: return False
         if i != num-1 and not iter.forward_char(): return False
      return True
      
   def apply_tag_exist_or_create(self, tag_property, property_value):
      """Check into the Tags Table whether the Tag Exists, if Not Creates it"""
      if property_value == "large": property_value = "h1"
      elif property_value == "largo": property_value = "h2"
      tag_name = tag_property + "_" + property_value
      tag = self.tag_table.lookup(str(tag_name))
      if tag == None:
         tag = gtk.TextTag(str(tag_name))
         if property_value == "heavy": tag.set_property(tag_property, pango.WEIGHT_HEAVY)
         elif property_value == "small": tag.set_property(tag_property, pango.SCALE_X_SMALL)
         elif property_value == "h1": tag.set_property(tag_property, pango.SCALE_XX_LARGE)
         elif property_value == "h2": tag.set_property(tag_property, pango.SCALE_X_LARGE)
         elif property_value == "italic": tag.set_property(tag_property, pango.STYLE_ITALIC)
         elif property_value == "single": tag.set_property(tag_property, pango.UNDERLINE_SINGLE)
         elif property_value == "true": tag.set_property(tag_property, True)
         elif property_value == "left": tag.set_property(tag_property, gtk.JUSTIFY_LEFT)
         elif property_value == "right": tag.set_property(tag_property, gtk.JUSTIFY_RIGHT)
         elif property_value == "center": tag.set_property(tag_property, gtk.JUSTIFY_CENTER)
         elif property_value[0:4] == "webs":
            tag.set_property("underline", pango.UNDERLINE_SINGLE)
            tag.set_property("foreground", "#00000000ffff")
         elif property_value[0:4] == "node":
            tag.set_property("underline", pango.UNDERLINE_SINGLE)
            tag.set_property("foreground", "#071c838e071c")
         elif property_value[0:4] == "file":
            tag.set_property("underline", pango.UNDERLINE_SINGLE)
            tag.set_property("foreground", "#8b8b69691414")
         elif property_value[0:4] == "fold":
            tag.set_property("underline", pango.UNDERLINE_SINGLE)
            tag.set_property("foreground", "#7f7f7f7f7f7f")
         else: tag.set_property(tag_property, property_value)
         self.tag_table.add(tag)
      return str(tag_name)
      
   def link_check_around_cursor(self):
      """Check if the cursor is on a link, in this case select the link and return the tag_property_value"""
      iter = self.curr_buffer.get_iter_at_mark(self.curr_buffer.get_insert())
      tags = iter.get_tags()
      for tag in tags:
         tag_name = tag.get_property("name")
         if tag_name[0:4] == "link": break
      else: return ""
      iter_end = iter.copy()
      if not iter_end.forward_to_tag_toggle(tag): return ""
      if not iter.backward_to_tag_toggle(tag): return ""
      self.curr_buffer.move_mark(self.curr_buffer.get_insert(), iter_end)
      self.curr_buffer.move_mark(self.curr_buffer.get_selection_bound(), iter)
      return tag_name[5:]
      
   def link_clicked(self, tag_property_value):
      """Function Called at Every Link Click"""
      vector = tag_property_value.split()
      if vector[0] == "webs":
         # link to webpage
         if self.weblink_custom_action[0]:
            subprocess.call(self.weblink_custom_action[1] % vector[1], shell=True)
         else: webbrowser.open(vector[1])
      elif vector[0] == "file":
         # link to file
         filepath = base64.b64decode(vector[1])
         if not os.path.isfile(filepath):
            support.dialog_error(_("The File Link '%s' is Not Valid") % filepath, self.window)
            return
         if self.filelink_custom_action[0]:
            subprocess.call(self.filelink_custom_action[1] % re.escape(filepath), shell=True)
         else:
            if sys.platform[0:3] == "win": os.startfile(filepath)
            else: subprocess.call("xdg-open %s" % re.escape(filepath), shell=True)
      elif vector[0] == "fold":
         # link to folder
         filepath = base64.b64decode(vector[1])
         if not os.path.isdir(filepath):
            support.dialog_error(_("The Folder Link '%s' is Not Valid") % filepath, self.window)
            return
         if self.folderlink_custom_action[0]:
            subprocess.call(self.folderlink_custom_action[1] % re.escape(filepath), shell=True)
         else:
            if sys.platform[0:3] == "win": os.startfile(filepath)
            else: subprocess.call("xdg-open %s" % re.escape(filepath), shell=True)
      elif vector[0] == "node":
         # link to a tree node
         tree_iter = self.get_tree_iter_from_node_id(long(vector[1]))
         if tree_iter == None:
            support.dialog_error(_("The Link Refers to a Node that Does Not Exist Anymore (Id = %s)") % vector[1], self.window)
            return
         self.treeview_safe_set_cursor(tree_iter)
         self.sourceview.grab_focus()
         self.sourceview.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(None)
         self.sourceview.set_tooltip_text(None)
         if len(vector) >= 3:
            if len(vector) == 3: anchor_name = vector[2]
            else: anchor_name = tag_property_value[len(vector[0]) + len(vector[1]) + 2:]
            iter_anchor = self.link_seek_for_anchor(anchor_name)
            if iter_anchor == None: support.dialog_warning(_("No anchor named '%s' found") % anchor_name, self.window)
            else:
               self.curr_buffer.place_cursor(iter_anchor)
               self.sourceview.scroll_to_mark(self.curr_buffer.get_insert(), 0.3)
      else: support.dialog_error("Tag Name Not Recognized! (%s)" % vector[0], self.window)
      
   def on_button_browse_for_file_to_link_to_clicked(self, *args):
      """The Button to browse for a file path on the links dialog was pressed"""
      if self.link_type == "file":
         filepath = support.dialog_file_select(curr_folder=self.pick_dir, parent=self.window)
      else: filepath = support.dialog_folder_select(curr_folder=self.pick_dir, parent=self.window)
      if filepath == None: return
      if self.link_type[0] == "file": self.pick_dir = os.path.dirname(filepath)
      self.glade.entry_file_to_link_to.set_text(filepath)
      
   def link_seek_for_anchor(self, anchor_name):
      """Given an Anchor Name, Seeks for it in the Current Node and Returns the Iter or None"""
      curr_iter = self.curr_buffer.get_start_iter()
      while 1:
         anchor = curr_iter.get_child_anchor()
         if anchor != None:
            if "pixbuf" in dir(anchor) and "anchor" in dir(anchor.pixbuf) and anchor.pixbuf.anchor == anchor_name:
               return curr_iter
         if not curr_iter.forward_char(): break
      return None
      
   def on_browse_anchors_button_clicked(self, *args):
      """Browse for Existing Anchors on the Selected Node"""
      self.anchors_liststore_exist_or_create()
      self.anchors_liststore.clear()
      model, tree_iter = self.treeviewselection_2.get_selected()
      curr_iter = self.treestore[tree_iter][2].get_start_iter()
      while 1:
         anchor = curr_iter.get_child_anchor()
         if anchor != None:
            if "pixbuf" in dir(anchor) and "anchor" in dir(anchor.pixbuf):
               self.anchors_liststore.append([anchor.pixbuf.anchor])
         if not curr_iter.forward_char(): break
      anchor_first_iter = self.anchors_liststore.get_iter_first()
      if anchor_first_iter == None:
         support.dialog_info(_("There are No Anchors in the Selected Node"), self.window)
         return
      else: self.anchors_treeview.set_cursor(self.anchors_liststore.get_path(anchor_first_iter))
      self.glade.anchor_enter_name_hbox.hide()
      self.glade.scrolledwindow_anchors_list.show()
      self.glade.anchorhandledialog.set_title(_("Choose Existing Anchor"))
      response = self.glade.anchorhandledialog.run()
      self.glade.anchorhandledialog.hide()
      if response != 1: return # the user aborted the operation
      listmodel, listiter = self.anchors_treeviewselection.get_selected()
      self.glade.link_anchor_entry.set_text(self.anchors_liststore[listiter][0])
      
   def anchors_liststore_exist_or_create(self):
      """If Does Not Exist => Create Anchors Browser Liststore"""
      if not "anchors_liststore" in dir(self):
         self.anchors_liststore = gtk.ListStore(str)
         self.anchors_treeview = gtk.TreeView(self.anchors_liststore)
         self.anchors_renderer_text = gtk.CellRendererText()
         self.anchors_column = gtk.TreeViewColumn(_("Anchor Name"), self.anchors_renderer_text, text=0)
         self.anchors_treeview.append_column(self.anchors_column)
         self.anchors_treeviewselection = self.anchors_treeview.get_selection()
         self.anchors_treeview.connect('button-press-event', self.on_mouse_button_clicked_anchors_list)
         self.glade.scrolledwindow_anchors_list.add(self.anchors_treeview)
         self.glade.scrolledwindow_anchors_list.show_all()
      
   def on_mouse_button_clicked_anchors_list(self, widget, event):
      """Catches mouse buttons clicks"""
      if event.button != 1: return
      if event.type == gtk.gdk._2BUTTON_PRESS: self.glade.anchorhandledialog_button_ok.clicked()
      
   def sourceview_cursor_and_tooltips_handler(self, x, y):
      """Looks at all tags covering the position (x, y) in the text view,
         and if one of them is a link, change the cursor to the HAND2 cursor"""
      hovering_link = False
      hovering_anchor = False
      hovering_todo_list = False
      text_iter = self.sourceview.get_iter_at_location(x, y)
      if text_iter.get_char() == cons.CHAR_SQ_BR_OPEN:
         text_iter_bis = text_iter.copy()
         hovering_todo_list = self.lists_handler.is_list_todo_beginning(text_iter_bis)
      elif text_iter.get_char() in [cons.CHAR_SPACE, cons.CHAR_X]:
         text_iter_bis = text_iter.copy()
         if text_iter_bis.backward_char():
            hovering_todo_list = self.lists_handler.is_list_todo_beginning(text_iter_bis)
      elif text_iter.get_char() == cons.CHAR_SQ_BR_CLOSE:
         text_iter_bis = text_iter.copy()
         if text_iter_bis.backward_chars(2):
            hovering_todo_list = self.lists_handler.is_list_todo_beginning(text_iter_bis)
      if hovering_todo_list:
         self.sourceview.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(gtk.gdk.Cursor(gtk.gdk.X_CURSOR))
         self.sourceview.set_tooltip_text(None)
         return
      tags = text_iter.get_tags()
      for tag in tags:
         tag_name = tag.get_property("name")
         if tag_name[0:4] == "link":
            hovering_link = True
            vector = tag_name[5:].split()
            if vector[0] in ["file", "fold"]: tooltip = base64.b64decode(vector[1])
            else:
               if vector[0] == "node" and long(vector[1]) in self.nodes_names_dict: tooltip = self.nodes_names_dict[long(vector[1])]
               else: tooltip = vector[1]
               if len(vector) >= 3:
                  if len(vector) == 3: anchor_name = vector[2]
                  else: anchor_name = tag_name[5 + len(vector[0]) + len(vector[1]) + 2:]
                  tooltip += "#" + anchor_name
            break
      else:
         iter_anchor = text_iter.copy()
         pixbuf = iter_anchor.get_pixbuf()
         if pixbuf != None and "anchor" in dir(pixbuf): hovering_anchor = True
         else:
            iter_anchor.backward_char()
            pixbuf = iter_anchor.get_pixbuf()
            if pixbuf != None and "anchor" in dir(pixbuf): hovering_anchor = True
      if hovering_link != self.hovering_over_link: self.hovering_over_link = hovering_link
      if hovering_anchor:
         self.sourceview.set_tooltip_text(pixbuf.anchor)
         return
      if self.hovering_over_link:
         self.sourceview.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND2))
         self.sourceview.set_tooltip_text(tooltip)
      else:
         self.sourceview.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(None)
         self.sourceview.set_tooltip_text(None)
   
   def on_sourceview_event_after(self, text_view, event):
      """Called after every event on the SourceView"""
      if event.type == gtk.gdk._2BUTTON_PRESS and event.button == 1:
         x, y = text_view.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET, int(event.x), int(event.y))
         iter_end = text_view.get_iter_at_location(x, y)
         iter_start = iter_end.copy()
         match = re.match('\w', iter_end.get_char()) # alphanumeric char
         if not match: return # double-click was not upon alphanumeric
         while match:
            if not iter_end.forward_char(): break # end of buffer
            match = re.match('\w', iter_end.get_char()) # alphanumeric char
         iter_start.backward_char()
         match = re.match('\w', iter_start.get_char()) # alphanumeric char
         while match:
            if not iter_start.backward_char(): break # start of buffer
            match = re.match('\w', iter_start.get_char()) # alphanumeric char
         if not match: iter_start.forward_char()
         self.curr_buffer.move_mark(self.curr_buffer.get_insert(), iter_start)
         self.curr_buffer.move_mark(self.curr_buffer.get_selection_bound(), iter_end)
      elif self.syntax_highlighting != cons.CUSTOM_COLORS_ID: return
      if event.type == gtk.gdk.BUTTON_PRESS:
         if event.button == 1:
            x, y = text_view.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET, int(event.x), int(event.y))
            text_iter = self.sourceview.get_iter_at_location(x, y)
            tags = text_iter.get_tags()
            # check whether we are hovering a link
            if tags:
               for tag in tags:
                  tag_name = tag.get_property("name")
                  if tag_name[0:4] == "link":
                     self.link_clicked(tag_name[5:])
                     break
            else:
               hovering_todo_list = False
               if text_iter.get_char() == cons.CHAR_SQ_BR_OPEN:
                  hovering_todo_list = self.lists_handler.is_list_todo_beginning(text_iter)
               elif text_iter.get_char() in [cons.CHAR_SPACE, cons.CHAR_X]:
                  if text_iter.backward_char():
                     hovering_todo_list = self.lists_handler.is_list_todo_beginning(text_iter)
               elif text_iter.get_char() == cons.CHAR_SQ_BR_CLOSE:
                  if text_iter.backward_chars(2):
                     hovering_todo_list = self.lists_handler.is_list_todo_beginning(text_iter)
               if hovering_todo_list:
                  self.lists_handler.todo_list_invert_checked_status(text_iter)
         elif event.button == 3 and not self.curr_buffer.get_has_selection():
            x, y = text_view.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET, int(event.x), int(event.y))
            text_iter = self.sourceview.get_iter_at_location(x, y)
            self.curr_buffer.place_cursor(text_iter)
      elif event.type == gtk.gdk.KEY_PRESS:
         keyname = gtk.gdk.keyval_name(event.keyval)
         if (event.state & gtk.gdk.SHIFT_MASK): # Shift held down
            if keyname == "Return":
               self.curr_buffer.insert(self.curr_buffer.get_iter_at_mark(self.curr_buffer.get_insert()), 3*cons.CHAR_SPACE)
         elif keyname == "Return":
            iter_insert = self.curr_buffer.get_iter_at_mark(self.curr_buffer.get_insert())
            if iter_insert == None: return False
            iter_start = iter_insert.copy()
            if iter_start.backward_chars(2) and iter_start.get_char() == cons.CHAR_NEWLINE: return False # former was an empty row
            list_info = self.lists_handler.get_paragraph_list_info(iter_start)
            if list_info[0] == None: return False # former was not a list
            # possible list quit
            iter_list_quit = iter_insert.copy()
            if (list_info[0] == 0 and iter_list_quit.backward_chars(3) and iter_list_quit.get_char() == cons.CHAR_LISTBUL):
               self.curr_buffer.delete(iter_list_quit, iter_insert)
               return False # former was an empty paragraph => list quit
            elif (list_info[0] == -1 and iter_list_quit.backward_chars(5) and iter_list_quit.get_char() == cons.CHAR_SQ_BR_OPEN):
               self.curr_buffer.delete(iter_list_quit, iter_insert)
               return False # former was an empty paragraph => list quit
            elif (list_info[0] > 0 and iter_list_quit.backward_chars(2) and iter_list_quit.get_char() == cons.CHAR_SPACE\
            and iter_list_quit.backward_char() and iter_list_quit.get_char() == '.'):
               iter_list_quit.backward_chars(len(str(list_info[0])))
               self.curr_buffer.delete(iter_list_quit, iter_insert)
               return False # former was an empty paragraph => list quit
            if list_info[1]: # multiple line paragraph
               iter_start = iter_insert.copy()
               iter_start.backward_chars(3)
               self.curr_buffer.delete(iter_start, iter_insert)
            if list_info[0] == 0: self.curr_buffer.insert(iter_insert, cons.CHAR_LISTBUL + cons.CHAR_SPACE)
            elif list_info[0] == -1: self.curr_buffer.insert(iter_insert, "[ ] ")
            else:
               curr_num = list_info[0] + 1
               self.curr_buffer.insert(iter_insert, '%s. ' % curr_num)
               self.lists_handler.list_adjust_ahead(curr_num, iter_insert.get_offset(), "num2num")
      return False
   
   def on_sourceview_motion_notify_event(self, text_view, event):
      """Update the cursor image if the pointer moved"""
      if not self.sourceview.get_cursor_visible(): self.sourceview.set_cursor_visible(True)
      if self.syntax_highlighting != cons.CUSTOM_COLORS_ID: return
      x, y = self.sourceview.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET, int(event.x), int(event.y))
      self.sourceview_cursor_and_tooltips_handler(x, y)
      return False
   
   def on_treeview_motion_notify_event(self, tree_view, event):
      """Update the tooltip if the pointer moved"""
      self.treeview.set_tooltip_text(None)
      self.treeview.trigger_tooltip_query()
      x, y = self.treeview.widget_to_tree_coords(int(event.x), int(event.y))
      pointer_tuple = self.treeview.get_path_at_pos(x, y)
      if pointer_tuple:
         pointer_iter = self.treestore.get_iter(pointer_tuple[0])
         tooltip_text = self.treestore[pointer_iter][4]
         if self.treestore[pointer_iter][7]: tooltip_text += "  -  " + _("Read Only")
         if self.treestore[pointer_iter][6]: tooltip_text += "  -  " + self.treestore[pointer_iter][6]
         self.treeview.set_tooltip_text(tooltip_text)
      return False
   
   def on_sourceview_visibility_notify_event(self, text_view, event):
      """Update the cursor image if the window becomes visible (e.g. when a window covering it got iconified)"""
      if self.syntax_highlighting != cons.CUSTOM_COLORS_ID: return
      wx, wy, mod = self.sourceview.window.get_pointer()
      bx, by = self.sourceview.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET, wx, wy)
      self.sourceview_cursor_and_tooltips_handler(bx, by)
      return False
   
   def on_window_n_tree_size_allocate_event(self, widget, allocation):
      """New Size Allocated"""
      if not self.curr_window_n_tree_width:
         self.curr_window_n_tree_width = {'window_width': self.window.get_allocation().width,
                                          'tree_width': self.scrolledwindow_tree.get_allocation().width}
      else:
         if not self.curr_buffer: return
         if self.curr_window_n_tree_width['window_width'] != self.window.get_allocation().width\
         or self.curr_window_n_tree_width['tree_width'] != self.scrolledwindow_tree.get_allocation().width:
            self.curr_window_n_tree_width['window_width'] = self.window.get_allocation().width
            self.curr_window_n_tree_width['tree_width'] = self.scrolledwindow_tree.get_allocation().width
            curr_iter = self.curr_buffer.get_start_iter()
            while 1:
               anchor = curr_iter.get_child_anchor()
               if anchor != None and "width_in_pixels" in dir(anchor) and not anchor.width_in_pixels:
                  self.codeboxes_handler.codebox_apply_width_height(anchor)
               if not curr_iter.forward_char(): break
            
   def get_text_window_width(self):
      """Get the Text Window Width"""
      return (self.window.get_allocation().width -\
              self.scrolledwindow_tree.get_allocation().width-\
              cons.MAIN_WIN_TO_TEXT_WIN_NORMALIZER)
   
   def remove_text_formatting(self, *args):
      """Cleans the Selected Text from All Formatting Tags"""
      if not self.node_sel_and_rich_text(): return
      if not self.curr_buffer.get_has_selection() and not self.apply_tag_try_automatic_bounds():
         support.dialog_warning(_("No Text is Selected"), self.window)
         return
      iter_sel_start, iter_sel_end = self.curr_buffer.get_selection_bounds()
      self.curr_buffer.remove_all_tags(iter_sel_start, iter_sel_end)
      self.update_window_save_needed()
      self.state_machine.update_state(self.treestore[self.curr_tree_iter][3])
      
   def bookmark_curr_node(self, *args):
      """Add the Current Node to the Bookmarks List"""
      if self.curr_tree_iter == None:
         support.dialog_warning(_("No Node is Selected"), self.window)
         return
      curr_node_id_str = str(self.treestore[self.curr_tree_iter][3])
      if not curr_node_id_str in self.bookmarks:
         self.bookmarks.append(curr_node_id_str)
         support.set_bookmarks_menu_items(self)
         self.update_window_save_needed()
      
   def bookmarks_handle(self, *args):
      """Handle the Bookmarks List"""
      if support.bookmarks_handle(self):
         self.update_window_save_needed()
      
   def tree_is_empty(self):
      """Return True if the treestore is empty"""
      if self.treestore.get_iter_first() == None: return True
      else: return False
